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