11dc9178dSRatan Gupta #include "config.h"
21dc9178dSRatan Gupta #include "snmp_conf_manager.hpp"
3212f53e8SRatan Gupta #include "snmp_serialize.hpp"
4213517baSRatan Gupta #include "snmp_util.hpp"
5213517baSRatan Gupta #include "xyz/openbmc_project/Common/error.hpp"
6213517baSRatan Gupta 
7213517baSRatan Gupta #include <phosphor-logging/elog-errors.hpp>
81dc9178dSRatan Gupta #include <phosphor-logging/log.hpp>
91dc9178dSRatan Gupta 
101dc9178dSRatan Gupta #include <experimental/filesystem>
111dc9178dSRatan Gupta 
12213517baSRatan Gupta #include <arpa/inet.h>
13213517baSRatan Gupta 
141dc9178dSRatan Gupta namespace phosphor
151dc9178dSRatan Gupta {
161dc9178dSRatan Gupta namespace network
171dc9178dSRatan Gupta {
181dc9178dSRatan Gupta namespace snmp
191dc9178dSRatan Gupta {
201dc9178dSRatan Gupta 
211dc9178dSRatan Gupta using namespace phosphor::logging;
22213517baSRatan Gupta using namespace sdbusplus::xyz::openbmc_project::Common::Error;
23213517baSRatan Gupta using Argument = xyz::openbmc_project::Common::InvalidArgument;
241dc9178dSRatan Gupta 
251dc9178dSRatan Gupta ConfManager::ConfManager(sdbusplus::bus::bus& bus, const char* objPath) :
26212f53e8SRatan Gupta     details::CreateIface(bus, objPath, true),
27212f53e8SRatan Gupta     dbusPersistentLocation(SNMP_CONF_PERSIST_PATH), bus(bus),
28212f53e8SRatan Gupta     objectPath(objPath)
291dc9178dSRatan Gupta {
301dc9178dSRatan Gupta }
311dc9178dSRatan Gupta 
32*d84e327dSRatan Gupta std::string ConfManager::client(std::string address, uint16_t port)
331dc9178dSRatan Gupta {
341dc9178dSRatan Gupta     auto clientEntry = this->clients.find(address);
35213517baSRatan Gupta     if (clientEntry != this->clients.end())
361dc9178dSRatan Gupta     {
37*d84e327dSRatan Gupta         log<level::ERR>("Client already configured"),
38*d84e327dSRatan Gupta             entry("ADDRESS=%s", address.c_str());
39*d84e327dSRatan Gupta         elog<InternalFailure>();
40213517baSRatan Gupta     }
41213517baSRatan Gupta     try
42213517baSRatan Gupta     {
43213517baSRatan Gupta         // just to check whether given address is valid or not.
44213517baSRatan Gupta         resolveAddress(address);
45213517baSRatan Gupta     }
46213517baSRatan Gupta     catch (InternalFailure& e)
47213517baSRatan Gupta     {
48213517baSRatan Gupta         log<level::ERR>("Not a valid address"),
49213517baSRatan Gupta             entry("ADDRESS=%s", address.c_str());
50213517baSRatan Gupta         elog<InvalidArgument>(Argument::ARGUMENT_NAME("Address"),
51213517baSRatan Gupta                               Argument::ARGUMENT_VALUE(address.c_str()));
52213517baSRatan Gupta     }
53*d84e327dSRatan Gupta 
541dc9178dSRatan Gupta     std::experimental::filesystem::path objPath;
551dc9178dSRatan Gupta     objPath /= objectPath;
561dc9178dSRatan Gupta     objPath /= generateId(address, port);
57*d84e327dSRatan Gupta     // create the D-Bus object
58212f53e8SRatan Gupta     auto client = std::make_unique<phosphor::network::snmp::Client>(
59212f53e8SRatan Gupta         bus, objPath.string().c_str(), *this, address, port);
60212f53e8SRatan Gupta     // save the D-Bus object
61212f53e8SRatan Gupta     serialize(*client, dbusPersistentLocation);
62212f53e8SRatan Gupta 
63212f53e8SRatan Gupta     this->clients.emplace(address, std::move(client));
64*d84e327dSRatan Gupta     return objPath.string();
651dc9178dSRatan Gupta }
661dc9178dSRatan Gupta 
671dc9178dSRatan Gupta std::string ConfManager::generateId(const std::string& address, uint16_t port)
681dc9178dSRatan Gupta {
691dc9178dSRatan Gupta     std::stringstream hexId;
701dc9178dSRatan Gupta     std::string hashString = address;
711dc9178dSRatan Gupta     hashString += std::to_string(port);
721dc9178dSRatan Gupta 
731dc9178dSRatan Gupta     // Only want 8 hex digits.
741dc9178dSRatan Gupta     hexId << std::hex << ((std::hash<std::string>{}(hashString)) & 0xFFFFFFFF);
751dc9178dSRatan Gupta     return hexId.str();
761dc9178dSRatan Gupta }
771dc9178dSRatan Gupta 
781dc9178dSRatan Gupta void ConfManager::deleteSNMPClient(const std::string& address)
791dc9178dSRatan Gupta {
801dc9178dSRatan Gupta     auto it = clients.find(address);
811dc9178dSRatan Gupta     if (it == clients.end())
821dc9178dSRatan Gupta     {
831dc9178dSRatan Gupta         log<level::ERR>("Unable to delete the snmp client.",
841dc9178dSRatan Gupta                         entry("ADDRESS=%s", address.c_str()));
851dc9178dSRatan Gupta         return;
861dc9178dSRatan Gupta     }
87212f53e8SRatan Gupta 
88212f53e8SRatan Gupta     std::error_code ec;
89212f53e8SRatan Gupta     // remove the persistent file
90212f53e8SRatan Gupta     fs::path fileName = dbusPersistentLocation;
91212f53e8SRatan Gupta     fileName /=
92f3fac222SGunnar Mills         it->second->address() + SEPARATOR + std::to_string(it->second->port());
93212f53e8SRatan Gupta 
94212f53e8SRatan Gupta     if (fs::exists(fileName))
95212f53e8SRatan Gupta     {
96212f53e8SRatan Gupta         if (!fs::remove(fileName, ec))
97212f53e8SRatan Gupta         {
98212f53e8SRatan Gupta             log<level::ERR>("Unable to delete the file",
99212f53e8SRatan Gupta                             entry("FILE=%s", fileName.c_str()),
100212f53e8SRatan Gupta                             entry("ERROR=%d", ec.value()));
101212f53e8SRatan Gupta         }
102212f53e8SRatan Gupta     }
103212f53e8SRatan Gupta     else
104212f53e8SRatan Gupta     {
105212f53e8SRatan Gupta         log<level::ERR>("File doesn't exist",
106212f53e8SRatan Gupta                         entry("FILE=%s", fileName.c_str()));
107212f53e8SRatan Gupta     }
108212f53e8SRatan Gupta     // remove the D-Bus Object.
1091dc9178dSRatan Gupta     this->clients.erase(it);
1101dc9178dSRatan Gupta }
1111dc9178dSRatan Gupta 
112212f53e8SRatan Gupta void ConfManager::restoreClients()
113212f53e8SRatan Gupta {
114212f53e8SRatan Gupta     if (!fs::exists(dbusPersistentLocation) ||
115212f53e8SRatan Gupta         fs::is_empty(dbusPersistentLocation))
116212f53e8SRatan Gupta     {
117212f53e8SRatan Gupta         return;
118212f53e8SRatan Gupta     }
119212f53e8SRatan Gupta 
120212f53e8SRatan Gupta     for (auto& confFile :
121212f53e8SRatan Gupta          fs::recursive_directory_iterator(dbusPersistentLocation))
122212f53e8SRatan Gupta     {
123212f53e8SRatan Gupta         if (!fs::is_regular_file(confFile))
124212f53e8SRatan Gupta         {
125212f53e8SRatan Gupta             continue;
126212f53e8SRatan Gupta         }
127212f53e8SRatan Gupta 
128212f53e8SRatan Gupta         auto managerID = confFile.path().filename().string();
129f3fac222SGunnar Mills         auto pos = managerID.find(SEPARATOR);
130212f53e8SRatan Gupta         auto ipaddress = managerID.substr(0, pos);
131212f53e8SRatan Gupta         auto port_str = managerID.substr(pos + 1);
132212f53e8SRatan Gupta         uint16_t port = stoi(port_str, nullptr);
133212f53e8SRatan Gupta 
134212f53e8SRatan Gupta         fs::path objPath = objectPath;
135212f53e8SRatan Gupta         objPath /= generateId(ipaddress, port);
136212f53e8SRatan Gupta         auto manager =
137212f53e8SRatan Gupta             std::make_unique<Client>(bus, objPath.string().c_str(), *this);
138212f53e8SRatan Gupta         if (deserialize(confFile.path(), *manager))
139212f53e8SRatan Gupta         {
140212f53e8SRatan Gupta             manager->emit_object_added();
141212f53e8SRatan Gupta             this->clients.emplace(ipaddress, std::move(manager));
142212f53e8SRatan Gupta         }
143212f53e8SRatan Gupta     }
144212f53e8SRatan Gupta }
145212f53e8SRatan Gupta 
1461dc9178dSRatan Gupta } // namespace snmp
1471dc9178dSRatan Gupta } // namespace network
1481dc9178dSRatan Gupta } // namespace phosphor
149