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