#include #include #include #include "snmp_pp/snmp_pp.h" #include "switch.h" #include "settings.h" #include "subscriber.h" #include "acl.h" #include "logger.h" #include "snmptable.h" #include "oids.h" using SSMD::Switch; using SSMD::SNMPTable; Switch::Switch(const Settings & settings, Snmp & snmp, const std::string & ip, const std::string & readCommunity, const std::string & writeCommunity, unsigned uplinkPort) : _settings(settings), _snmp(snmp), _ip(ip), _readCommunity(readCommunity), _writeCommunity(writeCommunity), _uplinkPort(uplinkPort), _nextUpACL(1), _nextDownACL(1), _aclsCreated(false) { } Switch::Switch(const Switch & rvalue) : _settings(rvalue._settings), _snmp(rvalue._snmp), _ip(rvalue._ip), _readCommunity(rvalue._readCommunity), _writeCommunity(rvalue._writeCommunity), _uplinkPort(rvalue._uplinkPort), _nextUpACL(rvalue._nextUpACL), _nextDownACL(rvalue._nextDownACL), _acls(rvalue._acls), _aclsCreated(rvalue._aclsCreated) { } Switch::~Switch() { if (_aclsCreated) { IpAddress addr(_ip.c_str()); if (!addr.valid()) { logger << "Switch::~Switch() - ivalid switch ip: '" << _ip << "'" << std::endl; return; } CTarget target(addr, _readCommunity.c_str(), _writeCommunity.c_str()); if (!target.valid()) { logger << "Switch::~Switch() - failed to create target for the switch '" << _ip << "'" << std::endl; return; } target.set_version(version2c); if (!checkProfiles(target)) { logger << "Switch::~Switch() - no upload and download profiles defined for the switch '" << _ip << "'" << std::endl; return; } if (!dropACLs(target, std::cerr)) { logger << "Switch::~Switch() - failed to drop ACLs for the switch '" << _ip << "'" << std::endl; return; } } } Switch & Switch::operator=(const Switch & rvalue) { _ip = rvalue._ip; _readCommunity = rvalue._readCommunity; _writeCommunity = rvalue._writeCommunity; _uplinkPort = rvalue._uplinkPort; _nextUpACL = rvalue._nextUpACL; _nextDownACL = rvalue._nextDownACL; _acls = rvalue._acls; _aclsCreated = rvalue._aclsCreated; return *this; } void Switch::addSubscriber(const Subscriber & subscriber) { _acls.push_back(ACL(_nextUpACL++, _settings.upProfileId(), subscriber.getMAC(), subscriber.getPort(), subscriber.getUpShape(), subscriber.getUpBurst(), true)); _acls.push_back(ACL(_nextDownACL++, _settings.downProfileId(), subscriber.getMAC(), _uplinkPort, subscriber.getDownShape(), subscriber.getDownBurst(), false)); } void Switch::sync() { IpAddress addr(_ip.c_str()); if (!addr.valid()) { logger << "Switch::sync() - ivalid switch ip: '" << _ip << "'" << std::endl; return; } CTarget target(addr, _readCommunity.c_str(), _writeCommunity.c_str()); if (!target.valid()) { logger << "Switch::sync() - failed to create target for the switch '" << _ip << "'" << std::endl; return; } target.set_version(version2c); if (!checkProfiles(target)) { logger << "Switch::sync() - no upload and download profiles defined for the switch '" << _ip << "'" << std::endl; return; } { std::ostream * stream = NULL; std::string fileName(_settings.scriptBase() + "/" + _ip + ".sh"); std::string newFileName(fileName + ".new"); if (_settings.dumpScripts()) { stream = new std::ofstream(newFileName.c_str()); *stream << "#!/bin/sh\n"; } else { stream = new std::stringstream; } if (!dropACLs(target, *stream)) { logger << "Switch::sync() - failed to drop ACLs for the switch '" << _ip << "'" << std::endl; delete stream; return; } if (!createACLs(target, *stream)) { logger << "Switch::sync() - failed to create ACLs for the switch '" << _ip << "'" << std::endl; delete stream; return; } delete stream; if (_settings.dumpScripts()) rename(newFileName.c_str(), fileName.c_str()); } if (_settings.isDebug()) { logger << "Switch::sync() - switch '" << _ip << "' synchronized successfully, ACLs: " << _acls.size() << std::endl; } } bool Switch::checkProfiles(const CTarget & target) { SNMPTable table(_snmp, target, Oid(swACLEtherRuleProfileID)); if (!table.valid()) { logger << "Switch::checkProfiles() - profiles SNMPTable is invalid for the switch '" << _ip << "'" << std::endl; return false; } if (table.empty()) { // Ok, just an empty table return false; } if (table.valueExists( static_cast(_settings.upProfileId()) ) && table.valueExists( static_cast(_settings.downProfileId()) )) { return true; } return false; } bool Switch::dropACLs(const CTarget & target, std::ostream & stream) { std::string upOidValue(swACLEtherRuleAccessID); upOidValue += "."; upOidValue += boost::lexical_cast(_settings.upProfileId()); std::string downOidValue(swACLEtherRuleAccessID); downOidValue += "."; downOidValue += boost::lexical_cast(_settings.downProfileId()); SNMPTable aclsUpTable(_snmp, target, Oid(upOidValue.c_str())); SNMPTable aclsDownTable(_snmp, target, Oid(downOidValue.c_str())); if (!aclsUpTable.valid()) { logger << "Switch::dropACLs() - upload profile acls SNMPTable is invalid for the switch '" << _ip << "'" << std::endl; return false; } if (!aclsDownTable.valid()) { logger << "Switch::dropACLs() - download profile acls SNMPTable is invalid for the switch '" << _ip << "'" << std::endl; return false; } if (!aclsUpTable.empty()) { if (!dropACLsByTable(target, _settings.upProfileId(), aclsUpTable, stream)) { logger << "Switch::dropACLs() - failed to drop acls from upload table for the switch '" << _ip << "'" << std::endl; return false; } } if (!aclsDownTable.empty()) { if (!dropACLsByTable(target, _settings.downProfileId(), aclsDownTable, stream)) { logger << "Switch::dropACLs() - failed to drop acls from download table for the switch '" << _ip << "'" << std::endl; return false; } } return true; } bool Switch::dropACLsByTable(const CTarget & target, unsigned profileId, const SNMPTable & table, std::ostream & stream) { std::string dropACLOidPrefix(swACLEtherRuleRowStatus); dropACLOidPrefix += "."; dropACLOidPrefix += boost::lexical_cast(profileId); SNMPList aclsList(table.getList()); SNMPList::const_iterator it(aclsList.begin()); size_t chunks = aclsList.size() / _settings.maxACLPerPDU() + 1; for (size_t i = 0; i < chunks && it != aclsList.end(); ++i) { Pdu pdu; if (_settings.dumpScripts()) stream << "snmpset -v2c -c" << _writeCommunity << " " << _ip; for (size_t j = 0; j < _settings.maxACLPerPDU() && it != aclsList.end(); ++j, ++it) { int id; if (int c = it->get_value(id) != SNMP_CLASS_SUCCESS) { logger << "Switch::dropACLsByTable() - failed to get ACL id for the switch '" << _ip << "'. Error message: '" << Snmp::error_msg(c) << "'" << std::endl; return false; } std::string dropACLOid(dropACLOidPrefix); dropACLOid += "."; dropACLOid += boost::lexical_cast(id); Vb vb(Oid(dropACLOid.c_str())); vb.set_value(int(6)); pdu += vb; if (_settings.dumpScripts()) stream << " " << dropACLOid << " i 6"; } if (_settings.dumpScripts()) stream << "\n"; if (int c = _snmp.set(pdu, target) != SNMP_CLASS_SUCCESS) { if (c != SNMP_ERROR_TOO_BIG) { logger << "Switch::dropACLsByTable() - failed to invoke Snmp::set for the switch '" << _ip << "'. Error message: '" << Snmp::error_msg(c) << "'" << std::endl; return false; } } } return true; } bool Switch::createACLs(const CTarget & target, std::ostream & stream) { std::vector::const_iterator it; size_t pos = 0; for (it = _acls.begin(); it != _acls.end(); ++it) { Pdu pdu; it->appendPdu(pdu); if (int c = _snmp.set(pdu, target) != SNMP_CLASS_SUCCESS) { if (c != SNMP_ERROR_TOO_BIG) { logger << "Switch::createACLs() - failed to invoke Snmp::set for the switch '" << _ip << "'. Error message: '" << Snmp::error_msg(c) << "'. Error occured at creation of " << (pos + 1) << " from " << _acls.size() << " ACL's" << std::endl; logger << "Switch::createACLs() - ACL dump: " << *it << std::endl; return false; } } pdu.clear(); _aclsCreated = true; ++pos; if (_settings.dumpScripts()) stream << "snmpset -v2c -c" << _writeCommunity << " " << _ip << " " << *it << "\n"; } return true; }