]> git.stg.codes - ssmd.git/blob - src/switch.cpp
Paranoid Pdu clearing
[ssmd.git] / src / switch.cpp
1 #include <boost/lexical_cast.hpp>
2
3 #include "snmp_pp/snmp_pp.h"
4
5 #include "switch.h"
6 #include "settings.h"
7 #include "subscriber.h"
8 #include "acl.h"
9 #include "logger.h"
10 #include "snmptable.h"
11 #include "oids.h"
12
13 using GTS::Switch;
14 using GTS::SNMPTable;
15
16 Switch::Switch(const Settings & settings,
17                Snmp & snmp,
18                const std::string & ip,
19                const std::string & readCommunity,
20                const std::string & writeCommunity,
21                unsigned uplinkPort)
22     : _settings(settings),
23       _snmp(snmp),
24       _ip(ip),
25       _readCommunity(readCommunity),
26       _writeCommunity(writeCommunity),
27       _uplinkPort(uplinkPort),
28       _nextUpACL(1),
29       _nextDownACL(1),
30       _aclsCreated(false)
31 {
32 }
33
34 Switch::Switch(const Switch & rvalue)
35     : _settings(rvalue._settings),
36       _snmp(rvalue._snmp),
37       _ip(rvalue._ip),
38       _readCommunity(rvalue._readCommunity),
39       _writeCommunity(rvalue._writeCommunity),
40       _uplinkPort(rvalue._uplinkPort),
41       _nextUpACL(rvalue._nextUpACL),
42       _nextDownACL(rvalue._nextDownACL),
43       _acls(rvalue._acls),
44       _aclsCreated(rvalue._aclsCreated)
45 {
46 }
47
48 Switch::~Switch()
49 {
50     if (_aclsCreated) {
51         IpAddress addr(_ip.c_str());
52         if (!addr.valid()) {
53             logger << "Switch::~Switch() - ivalid switch ip: '" << _ip << "'" << std::endl;
54             return;
55         }
56
57         CTarget target(addr, _readCommunity.c_str(), _writeCommunity.c_str());
58         if (!target.valid()) {
59             logger << "Switch::~Switch() - failed to create target for the switch '" << _ip << "'" << std::endl;
60             return;
61         }
62
63         target.set_version(version2c);
64
65         if (!checkProfiles(target)) {
66             logger << "Switch::~Switch() - no upload and download profiles defined for the switch '" << _ip << "'" << std::endl;
67             return;
68         }
69
70         if (!dropACLs(target)) {
71             logger << "Switch::~Switch() - failed to drop ACLs for the switch '" << _ip << "'" << std::endl;
72             return;
73         }
74     }
75 }
76
77 Switch & Switch::operator=(const Switch & rvalue)
78 {
79     _ip = rvalue._ip;
80     _readCommunity = rvalue._readCommunity;
81     _writeCommunity = rvalue._writeCommunity;
82     _uplinkPort = rvalue._uplinkPort;
83     _nextUpACL = rvalue._nextUpACL;
84     _nextDownACL = rvalue._nextDownACL;
85     _acls = rvalue._acls;
86     _aclsCreated = rvalue._aclsCreated;
87
88     return *this;
89 }
90
91 void Switch::addSubscriber(const Subscriber & subscriber)
92 {
93     _acls.push_back(ACL(_nextUpACL++,
94                         _settings.upProfileId(),
95                         subscriber.getMAC(),
96                         subscriber.getPort(),
97                         subscriber.getUpShape(),
98                         subscriber.getUpBurst(),
99                         true));
100     _acls.push_back(ACL(_nextDownACL++,
101                         _settings.downProfileId(),
102                         subscriber.getMAC(),
103                         _uplinkPort,
104                         subscriber.getDownShape(),
105                         subscriber.getDownBurst(),
106                         false));
107 }
108
109 void Switch::sync()
110 {
111     IpAddress addr(_ip.c_str());
112     if (!addr.valid()) {
113         logger << "Switch::sync() - ivalid switch ip: '" << _ip << "'" << std::endl;
114         return;
115     }
116
117     CTarget target(addr, _readCommunity.c_str(), _writeCommunity.c_str());
118     if (!target.valid()) {
119         logger << "Switch::sync() - failed to create target for the switch '" << _ip << "'" << std::endl;
120         return;
121     }
122
123     target.set_version(version2c);
124
125     if (!checkProfiles(target)) {
126         logger << "Switch::sync() - no upload and download profiles defined for the switch '" << _ip << "'" << std::endl;
127         return;
128     }
129
130     if (!dropACLs(target)) {
131         logger << "Switch::sync() - failed to drop ACLs for the switch '" << _ip << "'" << std::endl;
132         return;
133     }
134
135     if (!createACLs(target)) {
136         logger << "Switch::sync() - failed to create ACLs for the switch '" << _ip << "'" << std::endl;
137         return;
138     }
139
140     if (_settings.isDebug()) {
141         logger << "Switch::sync() - switch '" << _ip << "' synchronized successfully, ACLs: " << _acls.size() << std::endl;
142     }
143 }
144
145 bool Switch::checkProfiles(const CTarget & target)
146 {
147     SNMPTable table(_snmp, target, Oid(swACLEtherRuleProfileID));
148     if (!table.valid()) {
149         logger << "Switch::checkProfiles() - profiles SNMPTable is invalid for the switch '" << _ip << "'" << std::endl;
150         return false;
151     }
152     if (table.empty()) {
153         // Ok, just an empty table
154         return false;
155     }
156     if (table.valueExists(
157             static_cast<int>(_settings.upProfileId())
158         ) &&
159         table.valueExists(
160             static_cast<int>(_settings.downProfileId())
161         )) {
162         return true;
163     }
164     return false;
165 }
166
167 bool Switch::dropACLs(const CTarget & target)
168 {
169     std::string upOidValue(swACLEtherRuleAccessID);
170     upOidValue += ".";
171     upOidValue += boost::lexical_cast<std::string>(_settings.upProfileId());
172     std::string downOidValue(swACLEtherRuleAccessID);
173     downOidValue += ".";
174     downOidValue += boost::lexical_cast<std::string>(_settings.downProfileId());
175     SNMPTable aclsUpTable(_snmp, target, Oid(upOidValue.c_str()));
176     SNMPTable aclsDownTable(_snmp, target, Oid(downOidValue.c_str()));
177     if (!aclsUpTable.valid()) {
178         logger << "Switch::dropACLs() - upload profile acls SNMPTable is invalid for the switch '" << _ip << "'" << std::endl;
179         return false;
180     }
181     if (!aclsDownTable.valid()) {
182         logger << "Switch::dropACLs() - download profile acls SNMPTable is invalid for the switch '" << _ip << "'" << std::endl;
183         return false;
184     }
185     if (!aclsUpTable.empty()) {
186         if (!dropACLsByTable(target, _settings.upProfileId(), aclsUpTable)) {
187             logger << "Switch::dropACLs() - failed to drop acls from upload table for the switch '" << _ip << "'" << std::endl;
188             return false;
189         }
190     }
191     if (!aclsDownTable.empty()) {
192         if (!dropACLsByTable(target, _settings.downProfileId(), aclsDownTable)) {
193             logger << "Switch::dropACLs() - failed to drop acls from download table for the switch '" << _ip << "'" << std::endl;
194             return false;
195         }
196     }
197     return true;
198 }
199
200 bool Switch::dropACLsByTable(const CTarget & target, unsigned profileId, const SNMPTable & table)
201 {
202     std::string dropACLOidPrefix(swACLEtherRuleRowStatus);
203     dropACLOidPrefix += ".";
204     dropACLOidPrefix += boost::lexical_cast<std::string>(profileId);
205     SNMPList aclsList(table.getList());
206     SNMPList::const_iterator it(aclsList.begin());
207     size_t chunks = aclsList.size() / _settings.maxACLPerPDU() + 1;
208     for (size_t i = 0; i < chunks && it != aclsList.end(); ++i) {
209         Pdu pdu;
210         for (size_t j = 0; j < _settings.maxACLPerPDU() && it != aclsList.end(); ++j, ++it) {
211             int id;
212             if (int c = it->get_value(id) != SNMP_CLASS_SUCCESS) {
213                 logger << "Switch::dropACLsByTable() - failed to get ACL id for the switch '" << _ip << "'. Error message: '" << Snmp::error_msg(c) << "'" << std::endl;
214                 return false;
215             }
216             std::string dropACLOid(dropACLOidPrefix);
217             dropACLOid += ".";
218             dropACLOid += boost::lexical_cast<std::string>(id);
219             Vb vb(Oid(dropACLOid.c_str()));
220             vb.set_value(int(6));
221             pdu += vb;
222         }
223         if (int c = _snmp.set(pdu, target) != SNMP_CLASS_SUCCESS) {
224             if (c != SNMP_ERROR_TOO_BIG) {
225                 logger << "Switch::dropACLsByTable() - failed to invoke Snmp::set for the switch '" << _ip << "'. Error message: '" << Snmp::error_msg(c) << "'" << std::endl;
226                 return false;
227             }
228         }
229     }
230     return true;
231 }
232
233 bool Switch::createACLs(const CTarget & target)
234 {
235     std::vector<ACL>::const_iterator it;
236     size_t pos = 0;
237     for (it = _acls.begin(); it != _acls.end(); ++it) {
238         Pdu pdu;
239         it->appendPdu(pdu);
240         if (int c = _snmp.set(pdu, target) != SNMP_CLASS_SUCCESS) {
241             if (c != SNMP_ERROR_TOO_BIG) {
242                 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;
243                 logger << "Switch::createACLs() - ACL dump: " << *it << std::endl;
244                 return false;
245             }
246         }
247         pdu.clear();
248         _aclsCreated = true;
249         ++pos;
250     }
251     return true;
252 }