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