1 #include "config.h" 2 3 #include "network_manager.hpp" 4 5 #include "ipaddress.hpp" 6 #include "network_config.hpp" 7 #include "types.hpp" 8 #include "util.hpp" 9 10 #include <arpa/inet.h> 11 #include <dirent.h> 12 #include <net/if.h> 13 14 #include <algorithm> 15 #include <bitset> 16 #include <filesystem> 17 #include <fstream> 18 #include <map> 19 #include <phosphor-logging/elog-errors.hpp> 20 #include <phosphor-logging/log.hpp> 21 #include <string> 22 #include <xyz/openbmc_project/Common/error.hpp> 23 24 constexpr char SYSTEMD_BUSNAME[] = "org.freedesktop.systemd1"; 25 constexpr char SYSTEMD_PATH[] = "/org/freedesktop/systemd1"; 26 constexpr char SYSTEMD_INTERFACE[] = "org.freedesktop.systemd1.Manager"; 27 constexpr auto FirstBootFile = "/var/lib/network/firstBoot_"; 28 29 namespace phosphor 30 { 31 namespace network 32 { 33 34 extern std::unique_ptr<Timer> refreshObjectTimer; 35 extern std::unique_ptr<Timer> restartTimer; 36 using namespace phosphor::logging; 37 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 38 39 Manager::Manager(sdbusplus::bus::bus& bus, const char* objPath, 40 const std::string& path) : 41 details::VLANCreateIface(bus, objPath, true), 42 bus(bus), objectPath(objPath) 43 { 44 fs::path confDir(path); 45 setConfDir(confDir); 46 } 47 48 bool Manager::createDefaultNetworkFiles(bool force) 49 { 50 auto isCreated = false; 51 try 52 { 53 // Directory would have created before with 54 // setConfDir function. 55 if (force) 56 { 57 // Factory Reset case 58 // we need to forcefully write the files 59 // so delete the existing ones. 60 if (fs::is_directory(confDir)) 61 { 62 for (const auto& file : fs::directory_iterator(confDir)) 63 { 64 fs::remove(file.path()); 65 } 66 } 67 } 68 69 auto interfaceStrList = getInterfaces(); 70 for (const auto& interface : interfaceStrList) 71 { 72 // if the interface has '.' in the name, it means that this is a 73 // VLAN - don't create the network file. 74 if (interface.find(".") != std::string::npos) 75 { 76 continue; 77 } 78 79 auto fileName = systemd::config::networkFilePrefix + interface + 80 systemd::config::networkFileSuffix; 81 82 fs::path filePath = confDir; 83 filePath /= fileName; 84 85 // create the interface specific network file 86 // if not exist or we forcefully wants to write 87 // the network file. 88 89 if (force || !fs::is_regular_file(filePath.string())) 90 { 91 bmc::writeDHCPDefault(filePath.string(), interface); 92 log<level::INFO>("Created the default network file.", 93 entry("INTERFACE=%s", interface.c_str())); 94 isCreated = true; 95 } 96 } 97 } 98 catch (std::exception& e) 99 { 100 log<level::ERR>("Unable to create the default network file"); 101 } 102 return isCreated; 103 } 104 105 void Manager::setConfDir(const fs::path& dir) 106 { 107 confDir = dir; 108 109 if (!fs::exists(confDir)) 110 { 111 if (!fs::create_directories(confDir)) 112 { 113 log<level::ERR>("Unable to create the network conf dir", 114 entry("DIR=%s", confDir.c_str())); 115 elog<InternalFailure>(); 116 } 117 } 118 } 119 120 void Manager::createInterfaces() 121 { 122 // clear all the interfaces first 123 interfaces.clear(); 124 125 auto interfaceStrList = getInterfaces(); 126 127 for (auto& interface : interfaceStrList) 128 { 129 fs::path objPath = objectPath; 130 auto index = interface.find("."); 131 132 // interface can be of vlan type or normal ethernet interface. 133 // vlan interface looks like "interface.vlanid",so here by looking 134 // at the interface name we decide that we need 135 // to create the vlaninterface or normal physical interface. 136 if (index != std::string::npos) 137 { 138 // it is vlan interface 139 auto interfaceName = interface.substr(0, index); 140 auto vlanid = interface.substr(index + 1); 141 uint32_t vlanInt = std::stoul(vlanid); 142 143 interfaces[interfaceName]->loadVLAN(vlanInt); 144 continue; 145 } 146 // normal ethernet interface 147 objPath /= interface; 148 149 auto dhcp = getDHCPValue(confDir, interface); 150 151 auto intf = std::make_shared<phosphor::network::EthernetInterface>( 152 bus, objPath.string(), dhcp, *this); 153 154 intf->createIPAddressObjects(); 155 intf->createStaticNeighborObjects(); 156 intf->loadNameServers(); 157 158 this->interfaces.emplace( 159 std::make_pair(std::move(interface), std::move(intf))); 160 } 161 } 162 163 void Manager::createChildObjects() 164 { 165 // creates the ethernet interface dbus object. 166 createInterfaces(); 167 168 systemConf.reset(nullptr); 169 dhcpConf.reset(nullptr); 170 171 fs::path objPath = objectPath; 172 objPath /= "config"; 173 174 // create the system conf object. 175 systemConf = std::make_unique<phosphor::network::SystemConfiguration>( 176 bus, objPath.string(), *this); 177 // create the dhcp conf object. 178 objPath /= "dhcp"; 179 dhcpConf = std::make_unique<phosphor::network::dhcp::Configuration>( 180 bus, objPath.string(), *this); 181 } 182 183 ObjectPath Manager::vlan(IntfName interfaceName, uint32_t id) 184 { 185 return interfaces[interfaceName]->createVLAN(id); 186 } 187 188 void Manager::reset() 189 { 190 if (!createDefaultNetworkFiles(true)) 191 { 192 log<level::ERR>("Network Factory Reset failed."); 193 return; 194 // TODO: openbmc/openbmc#1721 - Log ResetFailed error here. 195 } 196 197 log<level::INFO>("Network Factory Reset done."); 198 } 199 200 // Need to merge the below function with the code which writes the 201 // config file during factory reset. 202 // TODO openbmc/openbmc#1751 203 void Manager::writeToConfigurationFile() 204 { 205 // write all the static ip address in the systemd-network conf file 206 for (const auto& intf : interfaces) 207 { 208 intf.second->writeConfigurationFile(); 209 } 210 restartTimers(); 211 } 212 213 #ifdef SYNC_MAC_FROM_INVENTORY 214 void Manager::setFistBootMACOnInterface( 215 const std::pair<std::string, std::string>& inventoryEthPair) 216 { 217 for (const auto& interface : interfaces) 218 { 219 if (interface.first == inventoryEthPair.first) 220 { 221 auto returnMAC = 222 interface.second->macAddress(inventoryEthPair.second); 223 if (returnMAC == inventoryEthPair.second) 224 { 225 log<level::INFO>("Set the MAC on "), 226 entry("interface : ", interface.first.c_str()), 227 entry("MAC : ", inventoryEthPair.second.c_str()); 228 std::error_code ec; 229 if (std::filesystem::is_directory("/var/lib/network", ec)) 230 { 231 std::ofstream persistentFile(FirstBootFile + 232 interface.first); 233 } 234 break; 235 } 236 else 237 { 238 log<level::INFO>("MAC is Not Set on ethernet Interface"); 239 } 240 } 241 } 242 } 243 244 #endif 245 246 void Manager::restartTimers() 247 { 248 using namespace std::chrono; 249 if (refreshObjectTimer && restartTimer) 250 { 251 restartTimer->restartOnce(restartTimeout); 252 refreshObjectTimer->restartOnce(refreshTimeout); 253 } 254 } 255 256 void Manager::restartSystemdUnit(const std::string& unit) 257 { 258 try 259 { 260 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 261 SYSTEMD_INTERFACE, "ResetFailedUnit"); 262 method.append(unit); 263 bus.call_noreply(method); 264 } 265 catch (const sdbusplus::exception::SdBusError& ex) 266 { 267 log<level::ERR>("Failed to reset failed unit", 268 entry("UNIT=%s", unit.c_str()), 269 entry("ERR=%s", ex.what())); 270 elog<InternalFailure>(); 271 } 272 273 try 274 { 275 auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH, 276 SYSTEMD_INTERFACE, "RestartUnit"); 277 method.append(unit.c_str(), "replace"); 278 bus.call_noreply(method); 279 } 280 catch (const sdbusplus::exception::SdBusError& ex) 281 { 282 log<level::ERR>("Failed to restart service", entry("ERR=%s", ex.what()), 283 entry("UNIT=%s", unit.c_str())); 284 elog<InternalFailure>(); 285 } 286 } 287 288 } // namespace network 289 } // namespace phosphor 290