11bbe3d1eSWilliam A. Kennington III #include "config.h" 21bbe3d1eSWilliam A. Kennington III 31bbe3d1eSWilliam A. Kennington III #include "network_manager.hpp" 41bbe3d1eSWilliam A. Kennington III #include "rtnetlink_server.hpp" 51bbe3d1eSWilliam A. Kennington III #include "types.hpp" 61bbe3d1eSWilliam A. Kennington III 71bbe3d1eSWilliam A. Kennington III #include <linux/netlink.h> 81bbe3d1eSWilliam A. Kennington III 91bbe3d1eSWilliam A. Kennington III #include <filesystem> 101bbe3d1eSWilliam A. Kennington III #include <fstream> 111bbe3d1eSWilliam A. Kennington III #include <functional> 121bbe3d1eSWilliam A. Kennington III #include <memory> 131bbe3d1eSWilliam A. Kennington III #ifdef SYNC_MAC_FROM_INVENTORY 141bbe3d1eSWilliam A. Kennington III #include <nlohmann/json.hpp> 151bbe3d1eSWilliam A. Kennington III #endif 161bbe3d1eSWilliam A. Kennington III #include <phosphor-logging/elog-errors.hpp> 171bbe3d1eSWilliam A. Kennington III #include <phosphor-logging/log.hpp> 181bbe3d1eSWilliam A. Kennington III #include <sdbusplus/bus.hpp> 191bbe3d1eSWilliam A. Kennington III #include <sdbusplus/bus/match.hpp> 201bbe3d1eSWilliam A. Kennington III #include <sdbusplus/server/manager.hpp> 211bbe3d1eSWilliam A. Kennington III #include <sdeventplus/event.hpp> 221bbe3d1eSWilliam A. Kennington III #include <xyz/openbmc_project/Common/error.hpp> 231bbe3d1eSWilliam A. Kennington III 241bbe3d1eSWilliam A. Kennington III using phosphor::logging::elog; 251bbe3d1eSWilliam A. Kennington III using phosphor::logging::entry; 261bbe3d1eSWilliam A. Kennington III using phosphor::logging::level; 271bbe3d1eSWilliam A. Kennington III using phosphor::logging::log; 281bbe3d1eSWilliam A. Kennington III using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 291bbe3d1eSWilliam A. Kennington III using DbusObjectPath = std::string; 301bbe3d1eSWilliam A. Kennington III using DbusInterface = std::string; 311bbe3d1eSWilliam A. Kennington III using PropertyValue = std::string; 321bbe3d1eSWilliam A. Kennington III 331bbe3d1eSWilliam A. Kennington III constexpr char NETWORK_CONF_DIR[] = "/etc/systemd/network"; 341bbe3d1eSWilliam A. Kennington III 351bbe3d1eSWilliam A. Kennington III constexpr char DEFAULT_OBJPATH[] = "/xyz/openbmc_project/network"; 361bbe3d1eSWilliam A. Kennington III 371bbe3d1eSWilliam A. Kennington III constexpr auto firstBootPath = "/var/lib/network/firstBoot_"; 381bbe3d1eSWilliam A. Kennington III constexpr auto configFile = "/usr/share/network/config.json"; 391bbe3d1eSWilliam A. Kennington III 401bbe3d1eSWilliam A. Kennington III constexpr auto invNetworkIntf = 411bbe3d1eSWilliam A. Kennington III "xyz.openbmc_project.Inventory.Item.NetworkInterface"; 421bbe3d1eSWilliam A. Kennington III 431bbe3d1eSWilliam A. Kennington III namespace phosphor 441bbe3d1eSWilliam A. Kennington III { 451bbe3d1eSWilliam A. Kennington III namespace network 461bbe3d1eSWilliam A. Kennington III { 471bbe3d1eSWilliam A. Kennington III 481bbe3d1eSWilliam A. Kennington III std::unique_ptr<phosphor::network::Manager> manager = nullptr; 491bbe3d1eSWilliam A. Kennington III std::unique_ptr<Timer> refreshObjectTimer = nullptr; 50c7cf25f7SWilliam A. Kennington III std::unique_ptr<Timer> reloadTimer = nullptr; 511bbe3d1eSWilliam A. Kennington III 521bbe3d1eSWilliam A. Kennington III #ifdef SYNC_MAC_FROM_INVENTORY 53c38b0710SPatrick Williams std::unique_ptr<sdbusplus::bus::match_t> EthInterfaceMatch = nullptr; 541bbe3d1eSWilliam A. Kennington III std::vector<std::string> first_boot_status; 551bbe3d1eSWilliam A. Kennington III 56c38b0710SPatrick Williams bool setInventoryMACOnSystem(sdbusplus::bus_t& bus, 571bbe3d1eSWilliam A. Kennington III const nlohmann::json& configJson, 581bbe3d1eSWilliam A. Kennington III const std::string& intfname) 591bbe3d1eSWilliam A. Kennington III { 601bbe3d1eSWilliam A. Kennington III try 611bbe3d1eSWilliam A. Kennington III { 621bbe3d1eSWilliam A. Kennington III auto inventoryMAC = mac_address::getfromInventory(bus, intfname); 631bbe3d1eSWilliam A. Kennington III if (!mac_address::toString(inventoryMAC).empty()) 641bbe3d1eSWilliam A. Kennington III { 651bbe3d1eSWilliam A. Kennington III log<level::INFO>("Mac Address in Inventory on "), 661bbe3d1eSWilliam A. Kennington III entry("Interface : ", intfname.c_str()), 671bbe3d1eSWilliam A. Kennington III entry("MAC Address :", 681bbe3d1eSWilliam A. Kennington III (mac_address::toString(inventoryMAC)).c_str()); 691bbe3d1eSWilliam A. Kennington III manager->setFistBootMACOnInterface(std::make_pair( 701bbe3d1eSWilliam A. Kennington III intfname.c_str(), mac_address::toString(inventoryMAC))); 711bbe3d1eSWilliam A. Kennington III first_boot_status.push_back(intfname.c_str()); 721bbe3d1eSWilliam A. Kennington III bool status = true; 731bbe3d1eSWilliam A. Kennington III for (const auto& keys : configJson.items()) 741bbe3d1eSWilliam A. Kennington III { 751bbe3d1eSWilliam A. Kennington III if (!(std::find(first_boot_status.begin(), 761bbe3d1eSWilliam A. Kennington III first_boot_status.end(), 771bbe3d1eSWilliam A. Kennington III keys.key()) != first_boot_status.end())) 781bbe3d1eSWilliam A. Kennington III { 791bbe3d1eSWilliam A. Kennington III log<level::INFO>("Interface MAC is NOT set from VPD"), 801bbe3d1eSWilliam A. Kennington III entry("INTERFACE", keys.key().c_str()); 811bbe3d1eSWilliam A. Kennington III status = false; 821bbe3d1eSWilliam A. Kennington III } 831bbe3d1eSWilliam A. Kennington III } 841bbe3d1eSWilliam A. Kennington III if (status) 851bbe3d1eSWilliam A. Kennington III { 861bbe3d1eSWilliam A. Kennington III log<level::INFO>("Removing the match for ethernet interfaces"); 871bbe3d1eSWilliam A. Kennington III phosphor::network::EthInterfaceMatch = nullptr; 881bbe3d1eSWilliam A. Kennington III } 891bbe3d1eSWilliam A. Kennington III } 901bbe3d1eSWilliam A. Kennington III else 911bbe3d1eSWilliam A. Kennington III { 921bbe3d1eSWilliam A. Kennington III log<level::INFO>("Nothing is present in Inventory"); 931bbe3d1eSWilliam A. Kennington III return false; 941bbe3d1eSWilliam A. Kennington III } 951bbe3d1eSWilliam A. Kennington III } 961bbe3d1eSWilliam A. Kennington III catch (const std::exception& e) 971bbe3d1eSWilliam A. Kennington III { 981bbe3d1eSWilliam A. Kennington III log<level::ERR>("Exception occurred during getting of MAC " 991bbe3d1eSWilliam A. Kennington III "address from Inventory"); 1001bbe3d1eSWilliam A. Kennington III return false; 1011bbe3d1eSWilliam A. Kennington III } 1021bbe3d1eSWilliam A. Kennington III return true; 1031bbe3d1eSWilliam A. Kennington III } 1041bbe3d1eSWilliam A. Kennington III 1051bbe3d1eSWilliam A. Kennington III // register the macthes to be monitored from inventory manager 106c38b0710SPatrick Williams void registerSignals(sdbusplus::bus_t& bus, const nlohmann::json& configJson) 1071bbe3d1eSWilliam A. Kennington III { 1081bbe3d1eSWilliam A. Kennington III log<level::INFO>("Registering the Inventory Signals Matcher"); 1091bbe3d1eSWilliam A. Kennington III 110c38b0710SPatrick Williams static std::unique_ptr<sdbusplus::bus::match_t> MacAddressMatch; 1111bbe3d1eSWilliam A. Kennington III 112c38b0710SPatrick Williams auto callback = [&](sdbusplus::message_t& m) { 1131bbe3d1eSWilliam A. Kennington III std::map<DbusObjectPath, 1141bbe3d1eSWilliam A. Kennington III std::map<DbusInterface, std::variant<PropertyValue>>> 1151bbe3d1eSWilliam A. Kennington III interfacesProperties; 1161bbe3d1eSWilliam A. Kennington III 1171bbe3d1eSWilliam A. Kennington III sdbusplus::message::object_path objPath; 1181bbe3d1eSWilliam A. Kennington III std::pair<std::string, std::string> ethPair; 1191bbe3d1eSWilliam A. Kennington III m.read(objPath, interfacesProperties); 1201bbe3d1eSWilliam A. Kennington III 1211bbe3d1eSWilliam A. Kennington III for (const auto& pattern : configJson.items()) 1221bbe3d1eSWilliam A. Kennington III { 1231bbe3d1eSWilliam A. Kennington III if (objPath.str.find(pattern.value()) != std::string::npos) 1241bbe3d1eSWilliam A. Kennington III { 1251bbe3d1eSWilliam A. Kennington III for (auto& interface : interfacesProperties) 1261bbe3d1eSWilliam A. Kennington III { 1271bbe3d1eSWilliam A. Kennington III if (interface.first == invNetworkIntf) 1281bbe3d1eSWilliam A. Kennington III { 1291bbe3d1eSWilliam A. Kennington III for (const auto& property : interface.second) 1301bbe3d1eSWilliam A. Kennington III { 1311bbe3d1eSWilliam A. Kennington III if (property.first == "MACAddress") 1321bbe3d1eSWilliam A. Kennington III { 1331bbe3d1eSWilliam A. Kennington III ethPair = std::make_pair( 1341bbe3d1eSWilliam A. Kennington III pattern.key(), 1351bbe3d1eSWilliam A. Kennington III std::get<std::string>(property.second)); 1361bbe3d1eSWilliam A. Kennington III break; 1371bbe3d1eSWilliam A. Kennington III } 1381bbe3d1eSWilliam A. Kennington III } 1391bbe3d1eSWilliam A. Kennington III break; 1401bbe3d1eSWilliam A. Kennington III } 1411bbe3d1eSWilliam A. Kennington III } 1421bbe3d1eSWilliam A. Kennington III if (!(ethPair.first.empty() || ethPair.second.empty())) 1431bbe3d1eSWilliam A. Kennington III { 1441bbe3d1eSWilliam A. Kennington III manager->setFistBootMACOnInterface(ethPair); 1451bbe3d1eSWilliam A. Kennington III } 1461bbe3d1eSWilliam A. Kennington III } 1471bbe3d1eSWilliam A. Kennington III } 1481bbe3d1eSWilliam A. Kennington III }; 1491bbe3d1eSWilliam A. Kennington III 150c38b0710SPatrick Williams MacAddressMatch = std::make_unique<sdbusplus::bus::match_t>( 1511bbe3d1eSWilliam A. Kennington III bus, 1521bbe3d1eSWilliam A. Kennington III "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 1531bbe3d1eSWilliam A. Kennington III "member='InterfacesAdded',path='/xyz/openbmc_project/" 1541bbe3d1eSWilliam A. Kennington III "inventory'", 1551bbe3d1eSWilliam A. Kennington III callback); 1561bbe3d1eSWilliam A. Kennington III } 1571bbe3d1eSWilliam A. Kennington III 158c38b0710SPatrick Williams void watchEthernetInterface(sdbusplus::bus_t& bus, 1591bbe3d1eSWilliam A. Kennington III const nlohmann::json& configJson) 1601bbe3d1eSWilliam A. Kennington III { 161c38b0710SPatrick Williams auto mycallback = [&](sdbusplus::message_t& m) { 1621bbe3d1eSWilliam A. Kennington III std::map<DbusObjectPath, 1631bbe3d1eSWilliam A. Kennington III std::map<DbusInterface, std::variant<PropertyValue>>> 1641bbe3d1eSWilliam A. Kennington III interfacesProperties; 1651bbe3d1eSWilliam A. Kennington III 1661bbe3d1eSWilliam A. Kennington III sdbusplus::message::object_path objPath; 1671bbe3d1eSWilliam A. Kennington III std::pair<std::string, std::string> ethPair; 1681bbe3d1eSWilliam A. Kennington III m.read(objPath, interfacesProperties); 1691bbe3d1eSWilliam A. Kennington III for (const auto& interfaces : interfacesProperties) 1701bbe3d1eSWilliam A. Kennington III { 1711bbe3d1eSWilliam A. Kennington III if (interfaces.first == 1721bbe3d1eSWilliam A. Kennington III "xyz.openbmc_project.Network.EthernetInterface") 1731bbe3d1eSWilliam A. Kennington III { 1741bbe3d1eSWilliam A. Kennington III for (const auto& property : interfaces.second) 1751bbe3d1eSWilliam A. Kennington III { 1761bbe3d1eSWilliam A. Kennington III if (property.first == "InterfaceName") 1771bbe3d1eSWilliam A. Kennington III { 1781bbe3d1eSWilliam A. Kennington III std::string infname = 1791bbe3d1eSWilliam A. Kennington III std::get<std::string>(property.second); 1801bbe3d1eSWilliam A. Kennington III 1811bbe3d1eSWilliam A. Kennington III if (configJson.find(infname) == configJson.end()) 1821bbe3d1eSWilliam A. Kennington III { 1831bbe3d1eSWilliam A. Kennington III // ethernet interface not found in configJSON 1841bbe3d1eSWilliam A. Kennington III // check if it is not sit0 interface, as it is 1851bbe3d1eSWilliam A. Kennington III // expected. 1861bbe3d1eSWilliam A. Kennington III if (infname != "sit0") 1871bbe3d1eSWilliam A. Kennington III { 1881bbe3d1eSWilliam A. Kennington III log<level::ERR>( 1891bbe3d1eSWilliam A. Kennington III "Wrong Interface Name in Config Json"); 1901bbe3d1eSWilliam A. Kennington III } 1911bbe3d1eSWilliam A. Kennington III } 1921bbe3d1eSWilliam A. Kennington III else 1931bbe3d1eSWilliam A. Kennington III { 1941bbe3d1eSWilliam A. Kennington III if (!phosphor::network::setInventoryMACOnSystem( 1951bbe3d1eSWilliam A. Kennington III bus, configJson, infname)) 1961bbe3d1eSWilliam A. Kennington III { 1971bbe3d1eSWilliam A. Kennington III phosphor::network::registerSignals(bus, 1981bbe3d1eSWilliam A. Kennington III configJson); 1991bbe3d1eSWilliam A. Kennington III phosphor::network::EthInterfaceMatch = nullptr; 2001bbe3d1eSWilliam A. Kennington III } 2011bbe3d1eSWilliam A. Kennington III } 2021bbe3d1eSWilliam A. Kennington III break; 2031bbe3d1eSWilliam A. Kennington III } 2041bbe3d1eSWilliam A. Kennington III } 2051bbe3d1eSWilliam A. Kennington III break; 2061bbe3d1eSWilliam A. Kennington III } 2071bbe3d1eSWilliam A. Kennington III } 2081bbe3d1eSWilliam A. Kennington III }; 2091bbe3d1eSWilliam A. Kennington III // Incase if phosphor-inventory-manager started early and the VPD is already 2101bbe3d1eSWilliam A. Kennington III // collected by the time network service has come up, better to check the 2111bbe3d1eSWilliam A. Kennington III // VPD directly and set the MAC Address on the respective Interface. 2121bbe3d1eSWilliam A. Kennington III 2131bbe3d1eSWilliam A. Kennington III bool registeredSignals = false; 2141bbe3d1eSWilliam A. Kennington III for (const auto& interfaceString : configJson.items()) 2151bbe3d1eSWilliam A. Kennington III { 2161bbe3d1eSWilliam A. Kennington III if (!std::filesystem::exists(firstBootPath + interfaceString.key()) && 2171bbe3d1eSWilliam A. Kennington III !registeredSignals) 2181bbe3d1eSWilliam A. Kennington III { 2191bbe3d1eSWilliam A. Kennington III 2201bbe3d1eSWilliam A. Kennington III log<level::INFO>( 2211bbe3d1eSWilliam A. Kennington III "First boot file is not present, check VPD for MAC"); 2221bbe3d1eSWilliam A. Kennington III phosphor::network::EthInterfaceMatch = std::make_unique< 223c38b0710SPatrick Williams sdbusplus::bus::match_t>( 2241bbe3d1eSWilliam A. Kennington III bus, 2251bbe3d1eSWilliam A. Kennington III "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 2261bbe3d1eSWilliam A. Kennington III "member='InterfacesAdded',path='/xyz/openbmc_project/network'", 2271bbe3d1eSWilliam A. Kennington III mycallback); 2281bbe3d1eSWilliam A. Kennington III registeredSignals = true; 2291bbe3d1eSWilliam A. Kennington III } 2301bbe3d1eSWilliam A. Kennington III } 2311bbe3d1eSWilliam A. Kennington III } 2321bbe3d1eSWilliam A. Kennington III 2331bbe3d1eSWilliam A. Kennington III #endif 2341bbe3d1eSWilliam A. Kennington III 2351bbe3d1eSWilliam A. Kennington III /** @brief refresh the network objects. */ 2361bbe3d1eSWilliam A. Kennington III void refreshObjects() 2371bbe3d1eSWilliam A. Kennington III { 2381bbe3d1eSWilliam A. Kennington III if (manager) 2391bbe3d1eSWilliam A. Kennington III { 2401bbe3d1eSWilliam A. Kennington III log<level::INFO>("Refreshing the objects."); 2411bbe3d1eSWilliam A. Kennington III manager->createChildObjects(); 2421bbe3d1eSWilliam A. Kennington III log<level::INFO>("Refreshing complete."); 2431bbe3d1eSWilliam A. Kennington III } 2441bbe3d1eSWilliam A. Kennington III } 2451bbe3d1eSWilliam A. Kennington III 246c7cf25f7SWilliam A. Kennington III void reloadNetworkd() 247c7cf25f7SWilliam A. Kennington III { 248c7cf25f7SWilliam A. Kennington III if (manager) 249c7cf25f7SWilliam A. Kennington III { 250c7cf25f7SWilliam A. Kennington III log<level::INFO>("Sending networkd reload"); 251c7cf25f7SWilliam A. Kennington III manager->doReloadConfigs(); 252c7cf25f7SWilliam A. Kennington III log<level::INFO>("Done networkd reload"); 253c7cf25f7SWilliam A. Kennington III } 254c7cf25f7SWilliam A. Kennington III } 255c7cf25f7SWilliam A. Kennington III 2561bbe3d1eSWilliam A. Kennington III void initializeTimers() 2571bbe3d1eSWilliam A. Kennington III { 2581bbe3d1eSWilliam A. Kennington III auto event = sdeventplus::Event::get_default(); 2591bbe3d1eSWilliam A. Kennington III refreshObjectTimer = 2601bbe3d1eSWilliam A. Kennington III std::make_unique<Timer>(event, std::bind(refreshObjects)); 261c7cf25f7SWilliam A. Kennington III reloadTimer = std::make_unique<Timer>(event, std::bind(reloadNetworkd)); 2621bbe3d1eSWilliam A. Kennington III } 2631bbe3d1eSWilliam A. Kennington III 2641bbe3d1eSWilliam A. Kennington III } // namespace network 2651bbe3d1eSWilliam A. Kennington III } // namespace phosphor 2661bbe3d1eSWilliam A. Kennington III 2671bbe3d1eSWilliam A. Kennington III int main(int /*argc*/, char** /*argv*/) 2681bbe3d1eSWilliam A. Kennington III { 2691bbe3d1eSWilliam A. Kennington III phosphor::network::initializeTimers(); 2701bbe3d1eSWilliam A. Kennington III 2711bbe3d1eSWilliam A. Kennington III auto bus = sdbusplus::bus::new_default(); 2721bbe3d1eSWilliam A. Kennington III 2731bbe3d1eSWilliam A. Kennington III // Need sd_event to watch for OCC device errors 2741bbe3d1eSWilliam A. Kennington III sd_event* event = nullptr; 2751bbe3d1eSWilliam A. Kennington III auto r = sd_event_default(&event); 2761bbe3d1eSWilliam A. Kennington III if (r < 0) 2771bbe3d1eSWilliam A. Kennington III { 2781bbe3d1eSWilliam A. Kennington III log<level::ERR>("Error creating a default sd_event handler"); 2791bbe3d1eSWilliam A. Kennington III return r; 2801bbe3d1eSWilliam A. Kennington III } 2811bbe3d1eSWilliam A. Kennington III 2821bbe3d1eSWilliam A. Kennington III phosphor::network::EventPtr eventPtr{event}; 2831bbe3d1eSWilliam A. Kennington III event = nullptr; 2841bbe3d1eSWilliam A. Kennington III 2851bbe3d1eSWilliam A. Kennington III // Attach the bus to sd_event to service user requests 2861bbe3d1eSWilliam A. Kennington III bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL); 2871bbe3d1eSWilliam A. Kennington III 2881bbe3d1eSWilliam A. Kennington III // Add sdbusplus Object Manager for the 'root' path of the network manager. 289c38b0710SPatrick Williams sdbusplus::server::manager_t objManager(bus, DEFAULT_OBJPATH); 2901bbe3d1eSWilliam A. Kennington III bus.request_name(DEFAULT_BUSNAME); 2911bbe3d1eSWilliam A. Kennington III 2921bbe3d1eSWilliam A. Kennington III phosphor::network::manager = std::make_unique<phosphor::network::Manager>( 2931bbe3d1eSWilliam A. Kennington III bus, DEFAULT_OBJPATH, NETWORK_CONF_DIR); 2941bbe3d1eSWilliam A. Kennington III 2951bbe3d1eSWilliam A. Kennington III // create the default network files if the network file 2961bbe3d1eSWilliam A. Kennington III // is not there for any interface. 297*9a1d9afaSWilliam A. Kennington III if (phosphor::network::manager->createDefaultNetworkFiles()) 2981bbe3d1eSWilliam A. Kennington III { 299bd649af9SWilliam A. Kennington III phosphor::network::manager->reloadConfigs(); 3001bbe3d1eSWilliam A. Kennington III } 3011bbe3d1eSWilliam A. Kennington III 3021bbe3d1eSWilliam A. Kennington III // RTNETLINK event handler 30332eef716SWilliam A. Kennington III phosphor::network::rtnetlink::Server svr(eventPtr); 3041bbe3d1eSWilliam A. Kennington III 3051bbe3d1eSWilliam A. Kennington III #ifdef SYNC_MAC_FROM_INVENTORY 3061bbe3d1eSWilliam A. Kennington III std::ifstream in(configFile); 3071bbe3d1eSWilliam A. Kennington III nlohmann::json configJson; 3081bbe3d1eSWilliam A. Kennington III in >> configJson; 3091bbe3d1eSWilliam A. Kennington III phosphor::network::watchEthernetInterface(bus, configJson); 3101bbe3d1eSWilliam A. Kennington III #endif 311bd649af9SWilliam A. Kennington III 312bd649af9SWilliam A. Kennington III // Trigger the initial object scan 31326c40a43SWilliam A. Kennington III // This is intentionally deferred, to ensure that systemd-networkd is 31426c40a43SWilliam A. Kennington III // fully configured. 31526c40a43SWilliam A. Kennington III phosphor::network::refreshObjectTimer->restartOnce( 31626c40a43SWilliam A. Kennington III phosphor::network::refreshTimeout); 317bd649af9SWilliam A. Kennington III 3181bbe3d1eSWilliam A. Kennington III sd_event_loop(eventPtr.get()); 3191bbe3d1eSWilliam A. Kennington III } 320