11dc9178dSRatan Gupta #include "config.h"
21334b7b3SPatrick Williams 
31dc9178dSRatan Gupta #include "snmp_conf_manager.hpp"
41334b7b3SPatrick Williams 
5212f53e8SRatan Gupta #include "snmp_serialize.hpp"
6213517baSRatan Gupta #include "snmp_util.hpp"
7213517baSRatan Gupta #include "xyz/openbmc_project/Common/error.hpp"
8213517baSRatan Gupta 
91334b7b3SPatrick Williams #include <arpa/inet.h>
101334b7b3SPatrick Williams 
11213517baSRatan Gupta #include <phosphor-logging/elog-errors.hpp>
124caedfbbSGeorge Liu #include <phosphor-logging/lg2.hpp>
131dc9178dSRatan Gupta 
1434d129a9SRatan Gupta #include <filesystem>
151dc9178dSRatan Gupta 
161dc9178dSRatan Gupta namespace phosphor
171dc9178dSRatan Gupta {
181dc9178dSRatan Gupta namespace network
191dc9178dSRatan Gupta {
201dc9178dSRatan Gupta namespace snmp
211dc9178dSRatan Gupta {
221dc9178dSRatan Gupta 
231dc9178dSRatan Gupta using namespace phosphor::logging;
24213517baSRatan Gupta using namespace sdbusplus::xyz::openbmc_project::Common::Error;
25213517baSRatan Gupta using Argument = xyz::openbmc_project::Common::InvalidArgument;
261dc9178dSRatan Gupta 
ConfManager(sdbusplus::bus_t & bus,const char * objPath)2787d3edd6SPatrick Williams ConfManager::ConfManager(sdbusplus::bus_t& bus, const char* objPath) :
28b9b4c7dbSPatrick Williams     details::CreateIface(bus, objPath,
29b9b4c7dbSPatrick Williams                          details::CreateIface::action::defer_emit),
30212f53e8SRatan Gupta     dbusPersistentLocation(SNMP_CONF_PERSIST_PATH), bus(bus),
31212f53e8SRatan Gupta     objectPath(objPath)
321334b7b3SPatrick Williams {}
331dc9178dSRatan Gupta 
client(std::string address,uint16_t port)34d84e327dSRatan Gupta std::string ConfManager::client(std::string address, uint16_t port)
351dc9178dSRatan Gupta {
369c4fed6dSRatan Gupta     // will throw exception if it is already configured.
379c4fed6dSRatan Gupta     checkClientConfigured(address, port);
38a7ff3850SRatan Gupta 
39213517baSRatan Gupta     try
40213517baSRatan Gupta     {
41213517baSRatan Gupta         // just to check whether given address is valid or not.
42213517baSRatan Gupta         resolveAddress(address);
43213517baSRatan Gupta     }
44c3600d86SPatrick Williams     catch (const InternalFailure& e)
45213517baSRatan Gupta     {
464caedfbbSGeorge Liu         lg2::error("{ADDRESS} is not a valid address", "ADDRESS", address);
47213517baSRatan Gupta         elog<InvalidArgument>(Argument::ARGUMENT_NAME("Address"),
48213517baSRatan Gupta                               Argument::ARGUMENT_VALUE(address.c_str()));
49213517baSRatan Gupta     }
50d84e327dSRatan Gupta 
5154d83f5aSGeorge Liu     lastClientId++;
52a7ff3850SRatan Gupta     // create the D-Bus object
5334d129a9SRatan Gupta     std::filesystem::path objPath;
541dc9178dSRatan Gupta     objPath /= objectPath;
55a7ff3850SRatan Gupta     objPath /= std::to_string(lastClientId);
56a7ff3850SRatan Gupta 
57212f53e8SRatan Gupta     auto client = std::make_unique<phosphor::network::snmp::Client>(
58212f53e8SRatan Gupta         bus, objPath.string().c_str(), *this, address, port);
59212f53e8SRatan Gupta 
60a7ff3850SRatan Gupta     // save the D-Bus object
61a7ff3850SRatan Gupta     serialize(lastClientId, *client, dbusPersistentLocation);
62a7ff3850SRatan Gupta 
63a7ff3850SRatan Gupta     this->clients.emplace(lastClientId, std::move(client));
64d84e327dSRatan Gupta     return objPath.string();
651dc9178dSRatan Gupta }
661dc9178dSRatan Gupta 
checkClientConfigured(const std::string & address,uint16_t port)679c4fed6dSRatan Gupta void ConfManager::checkClientConfigured(const std::string& address,
689c4fed6dSRatan Gupta                                         uint16_t port)
699c4fed6dSRatan Gupta {
709c4fed6dSRatan Gupta     if (address.empty())
719c4fed6dSRatan Gupta     {
724caedfbbSGeorge Liu         lg2::error("{ADDRESS} is not a valid address", "ADDRESS", address);
739c4fed6dSRatan Gupta         elog<InvalidArgument>(Argument::ARGUMENT_NAME("ADDRESS"),
749c4fed6dSRatan Gupta                               Argument::ARGUMENT_VALUE(address.c_str()));
759c4fed6dSRatan Gupta     }
769c4fed6dSRatan Gupta 
779c4fed6dSRatan Gupta     for (const auto& val : clients)
789c4fed6dSRatan Gupta     {
799c4fed6dSRatan Gupta         if (val.second.get()->address() == address &&
809c4fed6dSRatan Gupta             val.second.get()->port() == port)
819c4fed6dSRatan Gupta         {
824caedfbbSGeorge Liu             lg2::error("Client already exist");
839c4fed6dSRatan Gupta             // TODO Add the error(Object already exist) in the D-Bus interface
849c4fed6dSRatan Gupta             // then make the change here,meanwhile send the Internal Failure.
859c4fed6dSRatan Gupta             elog<InvalidArgument>(
869c4fed6dSRatan Gupta                 Argument::ARGUMENT_NAME("ADDRESS"),
879c4fed6dSRatan Gupta                 Argument::ARGUMENT_VALUE("Client already exist."));
889c4fed6dSRatan Gupta         }
899c4fed6dSRatan Gupta     }
909c4fed6dSRatan Gupta }
919c4fed6dSRatan Gupta 
deleteSNMPClient(Id id)92a7ff3850SRatan Gupta void ConfManager::deleteSNMPClient(Id id)
931dc9178dSRatan Gupta {
94a7ff3850SRatan Gupta     auto it = clients.find(id);
951dc9178dSRatan Gupta     if (it == clients.end())
961dc9178dSRatan Gupta     {
974caedfbbSGeorge Liu         lg2::error("Unable to delete the snmp client: {ID}", "ID", id);
981dc9178dSRatan Gupta         return;
991dc9178dSRatan Gupta     }
100212f53e8SRatan Gupta 
101212f53e8SRatan Gupta     std::error_code ec;
102212f53e8SRatan Gupta     // remove the persistent file
103212f53e8SRatan Gupta     fs::path fileName = dbusPersistentLocation;
104a7ff3850SRatan Gupta     fileName /= std::to_string(id);
105212f53e8SRatan Gupta 
106212f53e8SRatan Gupta     if (fs::exists(fileName))
107212f53e8SRatan Gupta     {
108212f53e8SRatan Gupta         if (!fs::remove(fileName, ec))
109212f53e8SRatan Gupta         {
1104caedfbbSGeorge Liu             lg2::error("Unable to delete {FILE}: {EC}", "FILE", fileName, "EC",
1114caedfbbSGeorge Liu                        ec.value());
112212f53e8SRatan Gupta         }
113212f53e8SRatan Gupta     }
114212f53e8SRatan Gupta     else
115212f53e8SRatan Gupta     {
1164caedfbbSGeorge Liu         lg2::error("{FILE} doesn't exist", "FILE", fileName);
117212f53e8SRatan Gupta     }
118212f53e8SRatan Gupta     // remove the D-Bus Object.
1191dc9178dSRatan Gupta     this->clients.erase(it);
1201dc9178dSRatan Gupta }
1211dc9178dSRatan Gupta 
restoreClients()122212f53e8SRatan Gupta void ConfManager::restoreClients()
123212f53e8SRatan Gupta {
124212f53e8SRatan Gupta     if (!fs::exists(dbusPersistentLocation) ||
125212f53e8SRatan Gupta         fs::is_empty(dbusPersistentLocation))
126212f53e8SRatan Gupta     {
127212f53e8SRatan Gupta         return;
128212f53e8SRatan Gupta     }
129212f53e8SRatan Gupta 
130212f53e8SRatan Gupta     for (auto& confFile :
131212f53e8SRatan Gupta          fs::recursive_directory_iterator(dbusPersistentLocation))
132212f53e8SRatan Gupta     {
133212f53e8SRatan Gupta         if (!fs::is_regular_file(confFile))
134212f53e8SRatan Gupta         {
135212f53e8SRatan Gupta             continue;
136212f53e8SRatan Gupta         }
137212f53e8SRatan Gupta 
138212f53e8SRatan Gupta         auto managerID = confFile.path().filename().string();
139a7ff3850SRatan Gupta         Id idNum = std::stol(managerID);
140212f53e8SRatan Gupta 
141212f53e8SRatan Gupta         fs::path objPath = objectPath;
142a7ff3850SRatan Gupta         objPath /= managerID;
143*edd70829SPatrick Williams         auto manager = std::make_unique<Client>(bus, objPath.string().c_str(),
144*edd70829SPatrick Williams                                                 *this);
145212f53e8SRatan Gupta         if (deserialize(confFile.path(), *manager))
146212f53e8SRatan Gupta         {
147212f53e8SRatan Gupta             manager->emit_object_added();
148a7ff3850SRatan Gupta             this->clients.emplace(idNum, std::move(manager));
149a7ff3850SRatan Gupta             if (idNum > lastClientId)
150a7ff3850SRatan Gupta             {
151a7ff3850SRatan Gupta                 lastClientId = idNum;
152a7ff3850SRatan Gupta             }
153212f53e8SRatan Gupta         }
154212f53e8SRatan Gupta     }
155212f53e8SRatan Gupta }
156212f53e8SRatan Gupta 
1571dc9178dSRatan Gupta } // namespace snmp
1581dc9178dSRatan Gupta } // namespace network
1591dc9178dSRatan Gupta } // namespace phosphor
160