1 #include "config.h" 2 3 #include "ethernet_interface.hpp" 4 5 #include "config_parser.hpp" 6 #include "network_manager.hpp" 7 #include "system_queries.hpp" 8 #include "util.hpp" 9 10 #include <fmt/compile.h> 11 #include <fmt/format.h> 12 #include <linux/rtnetlink.h> 13 #include <net/if.h> 14 15 #include <algorithm> 16 #include <filesystem> 17 #include <phosphor-logging/elog-errors.hpp> 18 #include <phosphor-logging/log.hpp> 19 #include <stdplus/raw.hpp> 20 #include <stdplus/zstring.hpp> 21 #include <string> 22 #include <unordered_map> 23 #include <variant> 24 #include <xyz/openbmc_project/Common/error.hpp> 25 26 namespace phosphor 27 { 28 namespace network 29 { 30 31 using namespace phosphor::logging; 32 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 33 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 34 using NotAllowedArgument = xyz::openbmc_project::Common::NotAllowed; 35 using Argument = xyz::openbmc_project::Common::InvalidArgument; 36 using std::literals::string_view_literals::operator""sv; 37 constexpr auto RESOLVED_SERVICE = "org.freedesktop.resolve1"; 38 constexpr auto RESOLVED_INTERFACE = "org.freedesktop.resolve1.Link"; 39 constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"; 40 constexpr auto RESOLVED_SERVICE_PATH = "/org/freedesktop/resolve1/link/"; 41 42 constexpr auto TIMESYNCD_SERVICE = "org.freedesktop.timesync1"; 43 constexpr auto TIMESYNCD_INTERFACE = "org.freedesktop.timesync1.Manager"; 44 constexpr auto TIMESYNCD_SERVICE_PATH = "/org/freedesktop/timesync1"; 45 46 constexpr auto METHOD_GET = "Get"; 47 48 template <typename Func> 49 inline decltype(std::declval<Func>()()) 50 ignoreError(std::string_view msg, stdplus::zstring_view intf, 51 decltype(std::declval<Func>()()) fallback, Func&& func) noexcept 52 { 53 try 54 { 55 return func(); 56 } 57 catch (const std::exception& e) 58 { 59 auto err = fmt::format("{} failed on {}: {}", msg, intf, e.what()); 60 log<level::ERR>(err.c_str(), entry("INTERFACE=%s", intf.c_str())); 61 } 62 return fallback; 63 } 64 65 static std::string makeObjPath(std::string_view root, std::string_view intf) 66 { 67 auto ret = fmt::format(FMT_COMPILE("{}/{}"), root, intf); 68 std::replace(ret.begin() + ret.size() - intf.size(), ret.end(), '.', '_'); 69 return ret; 70 } 71 72 EthernetInterface::EthernetInterface(sdbusplus::bus_t& bus, Manager& manager, 73 const InterfaceInfo& info, 74 std::string_view objRoot, 75 const config::Parser& config, 76 bool emitSignal, bool enabled) : 77 EthernetInterface(bus, manager, info, makeObjPath(objRoot, *info.name), 78 config, emitSignal, enabled) 79 { 80 } 81 82 EthernetInterface::EthernetInterface(sdbusplus::bus_t& bus, Manager& manager, 83 const InterfaceInfo& info, 84 std::string&& objPath, 85 const config::Parser& config, 86 bool emitSignal, bool enabled) : 87 Ifaces(bus, objPath.c_str(), 88 emitSignal ? Ifaces::action::defer_emit 89 : Ifaces::action::emit_no_signals), 90 manager(manager), bus(bus), objPath(std::move(objPath)), ifIdx(info.idx) 91 { 92 interfaceName(*info.name); 93 auto dhcpVal = getDHCPValue(config); 94 EthernetInterfaceIntf::dhcp4(dhcpVal.v4); 95 EthernetInterfaceIntf::dhcp6(dhcpVal.v6); 96 EthernetInterfaceIntf::ipv6AcceptRA(getIPv6AcceptRA(config)); 97 EthernetInterfaceIntf::nicEnabled(enabled); 98 { 99 const auto& gws = manager.getRouteTable().getDefaultGateway(); 100 auto it = gws.find(ifIdx); 101 if (it != gws.end()) 102 { 103 EthernetInterfaceIntf::defaultGateway(std::to_string(it->second)); 104 } 105 } 106 { 107 const auto& gws = manager.getRouteTable().getDefaultGateway6(); 108 auto it = gws.find(ifIdx); 109 if (it != gws.end()) 110 { 111 EthernetInterfaceIntf::defaultGateway6(std::to_string(it->second)); 112 } 113 } 114 115 EthernetInterfaceIntf::ntpServers( 116 config.map.getValueStrings("Network", "NTP")); 117 118 if (ifIdx > 0) 119 { 120 auto ethInfo = ignoreError("GetEthInfo", *info.name, {}, [&] { 121 return system::getEthInfo(*info.name); 122 }); 123 EthernetInterfaceIntf::autoNeg(ethInfo.autoneg); 124 EthernetInterfaceIntf::speed(ethInfo.speed); 125 } 126 127 updateInfo(info); 128 129 if (info.vlan_id) 130 { 131 if (!info.parent_idx) 132 { 133 std::runtime_error("Missing parent link"); 134 } 135 vlan.emplace(bus, this->objPath.c_str(), info, *this, emitSignal); 136 } 137 138 // Emit deferred signal. 139 if (emitSignal) 140 { 141 this->emit_object_added(); 142 } 143 } 144 145 void EthernetInterface::updateInfo(const InterfaceInfo& info) 146 { 147 EthernetInterfaceIntf::linkUp(info.flags & IFF_RUNNING); 148 if (info.mac) 149 { 150 MacAddressIntf::macAddress(std::to_string(*info.mac)); 151 } 152 if (info.mtu) 153 { 154 EthernetInterfaceIntf::mtu(*info.mtu); 155 } 156 } 157 158 bool EthernetInterface::originIsManuallyAssigned(IP::AddressOrigin origin) 159 { 160 return ( 161 #ifdef LINK_LOCAL_AUTOCONFIGURATION 162 (origin == IP::AddressOrigin::Static) 163 #else 164 (origin == IP::AddressOrigin::Static || 165 origin == IP::AddressOrigin::LinkLocal) 166 #endif 167 168 ); 169 } 170 171 void EthernetInterface::addAddr(const AddressInfo& info) 172 { 173 IP::AddressOrigin origin = IP::AddressOrigin::Static; 174 if (dhcpIsEnabled(info.ifaddr.getAddr())) 175 { 176 origin = IP::AddressOrigin::DHCP; 177 } 178 #ifdef LINK_LOCAL_AUTOCONFIGURATION 179 if (info.scope == RT_SCOPE_LINK) 180 { 181 origin = IP::AddressOrigin::LinkLocal; 182 } 183 #endif 184 185 auto it = addrs.find(info.ifaddr); 186 if (it == addrs.end()) 187 { 188 addrs.emplace(info.ifaddr, std::make_unique<IPAddress>( 189 bus, std::string_view(objPath), *this, 190 info.ifaddr, origin)); 191 } 192 else 193 { 194 it->second->IPIfaces::origin(origin); 195 } 196 } 197 198 void EthernetInterface::createIPAddressObjects() 199 { 200 addrs.clear(); 201 for (const auto& addr : system::getAddresses({.ifidx = ifIdx})) 202 { 203 manager.addAddress(addr); 204 } 205 } 206 207 void EthernetInterface::addStaticNeigh(const NeighborInfo& info) 208 { 209 if (!info.mac || !info.addr) 210 { 211 auto msg = fmt::format("Missing neighbor mac on {}\n", interfaceName()); 212 log<level::ERR>(msg.c_str()); 213 return; 214 } 215 216 if (auto it = staticNeighbors.find(*info.addr); it != staticNeighbors.end()) 217 { 218 it->second->NeighborObj::macAddress(std::to_string(*info.mac)); 219 } 220 else 221 { 222 staticNeighbors.emplace(*info.addr, std::make_unique<Neighbor>( 223 bus, std::string_view(objPath), 224 *this, *info.addr, *info.mac, 225 Neighbor::State::Permanent)); 226 } 227 } 228 229 void EthernetInterface::createStaticNeighborObjects() 230 { 231 staticNeighbors.clear(); 232 for (const auto& neighbor : system::getNeighbors({.ifidx = ifIdx})) 233 { 234 manager.addNeighbor(neighbor); 235 } 236 } 237 238 ObjectPath EthernetInterface::ip(IP::Protocol protType, std::string ipaddress, 239 uint8_t prefixLength, std::string) 240 { 241 InAddrAny addr; 242 try 243 { 244 switch (protType) 245 { 246 case IP::Protocol::IPv4: 247 addr = ToAddr<in_addr>{}(ipaddress); 248 break; 249 case IP::Protocol::IPv6: 250 addr = ToAddr<in6_addr>{}(ipaddress); 251 break; 252 default: 253 throw std::logic_error("Exhausted protocols"); 254 } 255 } 256 catch (const std::exception& e) 257 { 258 auto msg = fmt::format("Invalid IP `{}`: {}\n", ipaddress, e.what()); 259 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipaddress.c_str())); 260 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipaddress"), 261 Argument::ARGUMENT_VALUE(ipaddress.c_str())); 262 } 263 IfAddr ifaddr; 264 try 265 { 266 ifaddr = {addr, prefixLength}; 267 } 268 catch (const std::exception& e) 269 { 270 auto msg = fmt::format("Invalid prefix length `{}`: {}\n", prefixLength, 271 e.what()); 272 log<level::ERR>(msg.c_str(), 273 entry("PREFIXLENGTH=%" PRIu8, prefixLength)); 274 elog<InvalidArgument>( 275 Argument::ARGUMENT_NAME("prefixLength"), 276 Argument::ARGUMENT_VALUE(std::to_string(prefixLength).c_str())); 277 } 278 279 auto [it, _] = this->addrs.insert_or_assign( 280 ifaddr, 281 std::make_unique<IPAddress>(bus, std::string_view(objPath), *this, 282 ifaddr, IP::AddressOrigin::Static)); 283 284 writeConfigurationFile(); 285 manager.reloadConfigsNoRefresh(); 286 287 return it->second->getObjPath(); 288 } 289 290 ObjectPath EthernetInterface::neighbor(std::string ipAddress, 291 std::string macAddress) 292 { 293 InAddrAny addr; 294 try 295 { 296 addr = ToAddr<InAddrAny>{}(ipAddress); 297 } 298 catch (const std::exception& e) 299 { 300 auto msg = 301 fmt::format("Not a valid IP address `{}`: {}", ipAddress, e.what()); 302 log<level::ERR>(msg.c_str(), entry("ADDRESS=%s", ipAddress.c_str())); 303 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ipAddress"), 304 Argument::ARGUMENT_VALUE(ipAddress.c_str())); 305 } 306 307 ether_addr lladdr; 308 try 309 { 310 lladdr = ToAddr<ether_addr>{}(macAddress); 311 } 312 catch (const std::exception& e) 313 { 314 auto msg = fmt::format("Not a valid MAC address `{}`: {}", macAddress, 315 e.what()); 316 log<level::ERR>(msg.c_str(), 317 entry("MACADDRESS=%s", macAddress.c_str())); 318 elog<InvalidArgument>(Argument::ARGUMENT_NAME("macAddress"), 319 Argument::ARGUMENT_VALUE(macAddress.c_str())); 320 } 321 322 auto [it, _] = staticNeighbors.emplace( 323 addr, 324 std::make_unique<Neighbor>(bus, std::string_view(objPath), *this, addr, 325 lladdr, Neighbor::State::Permanent)); 326 327 writeConfigurationFile(); 328 manager.reloadConfigsNoRefresh(); 329 330 return it->second->getObjPath(); 331 } 332 333 bool EthernetInterface::ipv6AcceptRA(bool value) 334 { 335 if (ipv6AcceptRA() != EthernetInterfaceIntf::ipv6AcceptRA(value)) 336 { 337 writeConfigurationFile(); 338 manager.reloadConfigsNoRefresh(); 339 } 340 return value; 341 } 342 343 bool EthernetInterface::dhcp4(bool value) 344 { 345 if (dhcp4() != EthernetInterfaceIntf::dhcp4(value)) 346 { 347 writeConfigurationFile(); 348 manager.reloadConfigsNoRefresh(); 349 } 350 return value; 351 } 352 353 bool EthernetInterface::dhcp6(bool value) 354 { 355 if (dhcp6() != EthernetInterfaceIntf::dhcp6(value)) 356 { 357 writeConfigurationFile(); 358 manager.reloadConfigsNoRefresh(); 359 } 360 return value; 361 } 362 363 EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled(DHCPConf value) 364 { 365 auto old4 = EthernetInterfaceIntf::dhcp4(); 366 auto new4 = EthernetInterfaceIntf::dhcp4(value == DHCPConf::v4 || 367 value == DHCPConf::v4v6stateless || 368 value == DHCPConf::both); 369 auto old6 = EthernetInterfaceIntf::dhcp6(); 370 auto new6 = EthernetInterfaceIntf::dhcp6(value == DHCPConf::v6 || 371 value == DHCPConf::both); 372 auto oldra = EthernetInterfaceIntf::ipv6AcceptRA(); 373 auto newra = EthernetInterfaceIntf::ipv6AcceptRA( 374 value == DHCPConf::v6stateless || value == DHCPConf::v4v6stateless || 375 value == DHCPConf::v6 || value == DHCPConf::both); 376 377 if (old4 != new4 || old6 != new6 || oldra != newra) 378 { 379 writeConfigurationFile(); 380 manager.reloadConfigsNoRefresh(); 381 } 382 return value; 383 } 384 385 EthernetInterface::DHCPConf EthernetInterface::dhcpEnabled() const 386 { 387 if (dhcp6()) 388 { 389 return dhcp4() ? DHCPConf::both : DHCPConf::v6; 390 } 391 else if (dhcp4()) 392 { 393 return ipv6AcceptRA() ? DHCPConf::v4v6stateless : DHCPConf::v4; 394 } 395 return ipv6AcceptRA() ? DHCPConf::v6stateless : DHCPConf::none; 396 } 397 398 bool EthernetInterface::linkUp() const 399 { 400 if (ifIdx == 0) 401 { 402 return EthernetInterfaceIntf::linkUp(); 403 } 404 return system::intfIsRunning(interfaceName()); 405 } 406 407 size_t EthernetInterface::mtu() const 408 { 409 if (ifIdx == 0) 410 { 411 return EthernetInterfaceIntf::mtu(); 412 } 413 const auto ifname = interfaceName(); 414 return ignoreError("GetMTU", ifname, std::nullopt, 415 [&] { return system::getMTU(ifname); }) 416 .value_or(EthernetInterfaceIntf::mtu()); 417 } 418 419 size_t EthernetInterface::mtu(size_t value) 420 { 421 const size_t old = EthernetInterfaceIntf::mtu(); 422 if (value == old) 423 { 424 return value; 425 } 426 const auto ifname = interfaceName(); 427 return EthernetInterfaceIntf::mtu(ignoreError("SetMTU", ifname, old, [&] { 428 system::setMTU(ifname, value); 429 return value; 430 })); 431 } 432 433 bool EthernetInterface::nicEnabled(bool value) 434 { 435 if (value == EthernetInterfaceIntf::nicEnabled()) 436 { 437 return value; 438 } 439 440 EthernetInterfaceIntf::nicEnabled(value); 441 writeConfigurationFile(); 442 if (!value) 443 { 444 // We only need to bring down the interface, networkd will always bring 445 // up managed interfaces 446 manager.addReloadPreHook( 447 [ifname = interfaceName()]() { system::setNICUp(ifname, false); }); 448 } 449 manager.reloadConfigsNoRefresh(); 450 451 return value; 452 } 453 454 ServerList EthernetInterface::staticNameServers(ServerList value) 455 { 456 for (auto& ip : value) 457 { 458 try 459 { 460 ip = std::to_string(ToAddr<InAddrAny>{}(ip)); 461 } 462 catch (const std::exception& e) 463 { 464 auto msg = 465 fmt::format("Not a valid IP address `{}`: {}", ip, e.what()); 466 log<level::ERR>(msg.c_str()), entry("ADDRESS=%s", ip.c_str()); 467 elog<InvalidArgument>(Argument::ARGUMENT_NAME("StaticNameserver"), 468 Argument::ARGUMENT_VALUE(ip.c_str())); 469 } 470 } 471 try 472 { 473 EthernetInterfaceIntf::staticNameServers(value); 474 475 writeConfigurationFile(); 476 manager.reloadConfigsNoRefresh(); 477 } 478 catch (const InternalFailure& e) 479 { 480 log<level::ERR>("Exception processing DNS entries"); 481 } 482 return EthernetInterfaceIntf::staticNameServers(); 483 } 484 485 void EthernetInterface::loadNTPServers(const config::Parser& config) 486 { 487 EthernetInterfaceIntf::ntpServers(getNTPServerFromTimeSyncd()); 488 EthernetInterfaceIntf::staticNTPServers( 489 config.map.getValueStrings("Network", "NTP")); 490 } 491 492 void EthernetInterface::loadNameServers(const config::Parser& config) 493 { 494 EthernetInterfaceIntf::nameservers(getNameServerFromResolvd()); 495 EthernetInterfaceIntf::staticNameServers( 496 config.map.getValueStrings("Network", "DNS")); 497 } 498 499 ServerList EthernetInterface::getNTPServerFromTimeSyncd() 500 { 501 ServerList servers; // Variable to capture the NTP Server IPs 502 auto method = bus.new_method_call(TIMESYNCD_SERVICE, TIMESYNCD_SERVICE_PATH, 503 PROPERTY_INTERFACE, METHOD_GET); 504 505 method.append(TIMESYNCD_INTERFACE, "LinkNTPServers"); 506 507 try 508 { 509 auto reply = bus.call(method); 510 std::variant<ServerList> response; 511 reply.read(response); 512 servers = std::get<ServerList>(response); 513 } 514 catch (const sdbusplus::exception::SdBusError& e) 515 { 516 log<level::ERR>( 517 "Failed to get NTP server information from Systemd-Timesyncd"); 518 } 519 520 return servers; 521 } 522 523 ServerList EthernetInterface::getNameServerFromResolvd() 524 { 525 ServerList servers; 526 auto OBJ_PATH = fmt::format("{}{}", RESOLVED_SERVICE_PATH, ifIdx); 527 528 /* 529 The DNS property under org.freedesktop.resolve1.Link interface contains 530 an array containing all DNS servers currently used by resolved. It 531 contains similar information as the DNS server data written to 532 /run/systemd/resolve/resolv.conf. 533 534 Each structure in the array consists of a numeric network interface index, 535 an address family, and a byte array containing the DNS server address 536 (either 4 bytes in length for IPv4 or 16 bytes in lengths for IPv6). 537 The array contains DNS servers configured system-wide, including those 538 possibly read from a foreign /etc/resolv.conf or the DNS= setting in 539 /etc/systemd/resolved.conf, as well as per-interface DNS server 540 information either retrieved from systemd-networkd or configured by 541 external software via SetLinkDNS(). 542 */ 543 544 using type = std::vector<std::tuple<int32_t, std::vector<uint8_t>>>; 545 std::variant<type> name; // Variable to capture the DNS property 546 auto method = bus.new_method_call(RESOLVED_SERVICE, OBJ_PATH.c_str(), 547 PROPERTY_INTERFACE, METHOD_GET); 548 549 method.append(RESOLVED_INTERFACE, "DNS"); 550 551 try 552 { 553 auto reply = bus.call(method); 554 reply.read(name); 555 } 556 catch (const sdbusplus::exception_t& e) 557 { 558 log<level::ERR>("Failed to get DNS information from Systemd-Resolved"); 559 } 560 auto tupleVector = std::get_if<type>(&name); 561 for (auto i = tupleVector->begin(); i != tupleVector->end(); ++i) 562 { 563 int addressFamily = std::get<0>(*i); 564 std::vector<uint8_t>& ipaddress = std::get<1>(*i); 565 servers.push_back(std::to_string( 566 addrFromBuf(addressFamily, stdplus::raw::asView<char>(ipaddress)))); 567 } 568 return servers; 569 } 570 571 ObjectPath EthernetInterface::createVLAN(uint16_t id) 572 { 573 auto intfName = fmt::format(FMT_COMPILE("{}.{}"), interfaceName(), id); 574 auto idStr = std::to_string(id); 575 if (manager.interfaces.find(intfName) != manager.interfaces.end()) 576 { 577 log<level::ERR>("VLAN already exists", entry("VLANID=%u", id)); 578 elog<InvalidArgument>(Argument::ARGUMENT_NAME("VLANId"), 579 Argument::ARGUMENT_VALUE(idStr.c_str())); 580 } 581 582 auto objRoot = std::string_view(objPath).substr(0, objPath.rfind('/')); 583 auto macStr = MacAddressIntf::macAddress(); 584 std::optional<ether_addr> mac; 585 if (!macStr.empty()) 586 { 587 mac.emplace(ToAddr<ether_addr>{}(macStr)); 588 } 589 auto info = InterfaceInfo{ 590 .idx = 0, // TODO: Query the correct value after creation 591 .flags = 0, 592 .name = intfName, 593 .mac = std::move(mac), 594 .mtu = mtu(), 595 .parent_idx = ifIdx, 596 .vlan_id = id, 597 }; 598 599 // Pass the parents nicEnabled property, so that the child 600 // VLAN interface can inherit. 601 auto vlanIntf = std::make_unique<EthernetInterface>( 602 bus, manager, info, objRoot, config::Parser(), /*emit=*/true, 603 nicEnabled()); 604 ObjectPath ret = vlanIntf->objPath; 605 606 manager.interfaces.emplace(intfName, std::move(vlanIntf)); 607 608 // write the device file for the vlan interface. 609 config::Parser config; 610 auto& netdev = config.map["NetDev"].emplace_back(); 611 netdev["Name"].emplace_back(intfName); 612 netdev["Kind"].emplace_back("vlan"); 613 config.map["VLAN"].emplace_back()["Id"].emplace_back(std::move(idStr)); 614 config.writeFile(config::pathForIntfDev(manager.getConfDir(), intfName)); 615 616 writeConfigurationFile(); 617 manager.reloadConfigsNoRefresh(); 618 619 return ret; 620 } 621 622 ServerList EthernetInterface::staticNTPServers(ServerList value) 623 { 624 try 625 { 626 EthernetInterfaceIntf::staticNTPServers(value); 627 628 writeConfigurationFile(); 629 manager.reloadConfigsNoRefresh(); 630 } 631 catch (InternalFailure& e) 632 { 633 log<level::ERR>("Exception processing NTP entries"); 634 } 635 return EthernetInterfaceIntf::staticNTPServers(); 636 } 637 638 ServerList EthernetInterface::ntpServers(ServerList /*servers*/) 639 { 640 elog<NotAllowed>(NotAllowedArgument::REASON("ReadOnly Property")); 641 } 642 // Need to merge the below function with the code which writes the 643 // config file during factory reset. 644 // TODO openbmc/openbmc#1751 645 646 void EthernetInterface::writeConfigurationFile() 647 { 648 config::Parser config; 649 config.map["Match"].emplace_back()["Name"].emplace_back(interfaceName()); 650 { 651 auto& link = config.map["Link"].emplace_back(); 652 #ifdef PERSIST_MAC 653 auto mac = MacAddressIntf::macAddress(); 654 if (!mac.empty()) 655 { 656 link["MACAddress"].emplace_back(mac); 657 } 658 #endif 659 if (!EthernetInterfaceIntf::nicEnabled()) 660 { 661 link["Unmanaged"].emplace_back("yes"); 662 } 663 } 664 { 665 auto& network = config.map["Network"].emplace_back(); 666 auto& lla = network["LinkLocalAddressing"]; 667 #ifdef LINK_LOCAL_AUTOCONFIGURATION 668 lla.emplace_back("yes"); 669 #else 670 lla.emplace_back("no"); 671 #endif 672 network["IPv6AcceptRA"].emplace_back(ipv6AcceptRA() ? "true" : "false"); 673 network["DHCP"].emplace_back(dhcp4() ? (dhcp6() ? "true" : "ipv4") 674 : (dhcp6() ? "ipv6" : "false")); 675 { 676 auto& vlans = network["VLAN"]; 677 for (const auto& [_, intf] : manager.interfaces) 678 { 679 if (intf->vlan && intf->vlan->parentIdx == ifIdx) 680 { 681 vlans.emplace_back(intf->interfaceName()); 682 } 683 } 684 } 685 { 686 auto& ntps = network["NTP"]; 687 for (const auto& ntp : EthernetInterfaceIntf::staticNTPServers()) 688 { 689 ntps.emplace_back(ntp); 690 } 691 } 692 { 693 auto& dnss = network["DNS"]; 694 for (const auto& dns : EthernetInterfaceIntf::staticNameServers()) 695 { 696 dnss.emplace_back(dns); 697 } 698 } 699 { 700 auto& address = network["Address"]; 701 for (const auto& addr : addrs) 702 { 703 if (originIsManuallyAssigned(addr.second->origin())) 704 { 705 address.emplace_back( 706 fmt::format("{}/{}", addr.second->address(), 707 addr.second->prefixLength())); 708 } 709 } 710 } 711 { 712 auto& gateways = network["Gateway"]; 713 if (!dhcp4()) 714 { 715 auto gateway = EthernetInterfaceIntf::defaultGateway(); 716 if (!gateway.empty()) 717 { 718 gateways.emplace_back(gateway); 719 } 720 } 721 722 if (!dhcp6()) 723 { 724 auto gateway6 = EthernetInterfaceIntf::defaultGateway6(); 725 if (!gateway6.empty()) 726 { 727 gateways.emplace_back(gateway6); 728 } 729 } 730 } 731 } 732 config.map["IPv6AcceptRA"].emplace_back()["DHCPv6Client"].emplace_back( 733 dhcp6() ? "true" : "false"); 734 { 735 auto& neighbors = config.map["Neighbor"]; 736 for (const auto& sneighbor : staticNeighbors) 737 { 738 auto& neighbor = neighbors.emplace_back(); 739 neighbor["Address"].emplace_back(sneighbor.second->ipAddress()); 740 neighbor["MACAddress"].emplace_back(sneighbor.second->macAddress()); 741 } 742 } 743 { 744 auto& dhcp = config.map["DHCP"].emplace_back(); 745 dhcp["ClientIdentifier"].emplace_back("mac"); 746 if (manager.getDHCPConf()) 747 { 748 const auto& conf = *manager.getDHCPConf(); 749 auto dns_enabled = conf.dnsEnabled() ? "true" : "false"; 750 dhcp["UseDNS"].emplace_back(dns_enabled); 751 dhcp["UseDomains"].emplace_back(dns_enabled); 752 dhcp["UseNTP"].emplace_back(conf.ntpEnabled() ? "true" : "false"); 753 dhcp["UseHostname"].emplace_back(conf.hostNameEnabled() ? "true" 754 : "false"); 755 dhcp["SendHostname"].emplace_back( 756 conf.sendHostNameEnabled() ? "true" : "false"); 757 } 758 } 759 auto path = config::pathForIntfConf(manager.getConfDir(), interfaceName()); 760 config.writeFile(path); 761 auto msg = fmt::format("Wrote networkd file: {}", path.native()); 762 log<level::INFO>(msg.c_str(), entry("FILE=%s", path.c_str())); 763 } 764 765 std::string EthernetInterface::macAddress([[maybe_unused]] std::string value) 766 { 767 if (vlan) 768 { 769 log<level::ERR>("Tried to set MAC address on VLAN"); 770 elog<InternalFailure>(); 771 } 772 #ifdef PERSIST_MAC 773 ether_addr newMAC; 774 try 775 { 776 newMAC = ToAddr<ether_addr>{}(value); 777 } 778 catch (const std::invalid_argument&) 779 { 780 log<level::ERR>("MACAddress is not valid.", 781 entry("MAC=%s", value.c_str())); 782 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"), 783 Argument::ARGUMENT_VALUE(value.c_str())); 784 } 785 if (!mac_address::isUnicast(newMAC)) 786 { 787 log<level::ERR>("MACAddress is not valid.", 788 entry("MAC=%s", value.c_str())); 789 elog<InvalidArgument>(Argument::ARGUMENT_NAME("MACAddress"), 790 Argument::ARGUMENT_VALUE(value.c_str())); 791 } 792 793 auto interface = interfaceName(); 794 auto validMAC = std::to_string(newMAC); 795 796 // We don't need to update the system if the address is unchanged 797 ether_addr oldMAC = ToAddr<ether_addr>{}(MacAddressIntf::macAddress()); 798 if (newMAC != oldMAC) 799 { 800 // Update everything that depends on the MAC value 801 for (const auto& [_, intf] : manager.interfaces) 802 { 803 if (intf->vlan && intf->vlan->parentIdx == ifIdx) 804 { 805 intf->MacAddressIntf::macAddress(validMAC); 806 } 807 } 808 MacAddressIntf::macAddress(validMAC); 809 810 writeConfigurationFile(); 811 manager.addReloadPreHook([interface]() { 812 // The MAC and LLADDRs will only update if the NIC is already down 813 system::setNICUp(interface, false); 814 }); 815 manager.reloadConfigsNoRefresh(); 816 } 817 818 #ifdef HAVE_UBOOT_ENV 819 // Ensure that the valid address is stored in the u-boot-env 820 auto envVar = interfaceToUbootEthAddr(interface); 821 if (envVar) 822 { 823 // Trimming MAC addresses that are out of range. eg: AA:FF:FF:FF:FF:100; 824 // and those having more than 6 bytes. eg: AA:AA:AA:AA:AA:AA:BB 825 execute("/sbin/fw_setenv", "fw_setenv", envVar->c_str(), 826 validMAC.c_str()); 827 } 828 #endif // HAVE_UBOOT_ENV 829 830 return value; 831 #else 832 elog<NotAllowed>( 833 NotAllowedArgument::REASON("Writing MAC address is not allowed")); 834 #endif // PERSIST_MAC 835 } 836 837 void EthernetInterface::deleteAll() 838 { 839 // clear all the ip on the interface 840 addrs.clear(); 841 842 writeConfigurationFile(); 843 manager.reloadConfigsNoRefresh(); 844 } 845 846 std::string EthernetInterface::defaultGateway(std::string gateway) 847 { 848 try 849 { 850 if (!gateway.empty()) 851 { 852 gateway = std::to_string(ToAddr<in_addr>{}(gateway)); 853 } 854 } 855 catch (const std::exception& e) 856 { 857 auto msg = fmt::format("Invalid v4 GW `{}`: {}", gateway, e.what()); 858 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str())); 859 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"), 860 Argument::ARGUMENT_VALUE(gateway.c_str())); 861 } 862 863 if (EthernetInterfaceIntf::defaultGateway() == gateway) 864 { 865 return gateway; 866 } 867 EthernetInterfaceIntf::defaultGateway(gateway); 868 869 writeConfigurationFile(); 870 manager.reloadConfigsNoRefresh(); 871 872 return gateway; 873 } 874 875 std::string EthernetInterface::defaultGateway6(std::string gateway) 876 { 877 try 878 { 879 if (!gateway.empty()) 880 { 881 gateway = std::to_string(ToAddr<in6_addr>{}(gateway)); 882 } 883 } 884 catch (const std::exception& e) 885 { 886 auto msg = fmt::format("Invalid v6 GW `{}`: {}", gateway, e.what()); 887 log<level::ERR>(msg.c_str(), entry("GATEWAY=%s", gateway.c_str())); 888 elog<InvalidArgument>(Argument::ARGUMENT_NAME("GATEWAY"), 889 Argument::ARGUMENT_VALUE(gateway.c_str())); 890 } 891 892 if (EthernetInterfaceIntf::defaultGateway6() == gateway) 893 { 894 return gateway; 895 } 896 EthernetInterfaceIntf::defaultGateway6(gateway); 897 898 writeConfigurationFile(); 899 manager.reloadConfigsNoRefresh(); 900 901 return gateway; 902 } 903 904 EthernetInterface::VlanProperties::VlanProperties( 905 sdbusplus::bus_t& bus, stdplus::const_zstring objPath, 906 const InterfaceInfo& info, EthernetInterface& eth, bool emitSignal) : 907 VlanIfaces(bus, objPath.c_str(), 908 emitSignal ? VlanIfaces::action::defer_emit 909 : VlanIfaces::action::emit_no_signals), 910 parentIdx(*info.parent_idx), eth(eth) 911 { 912 VlanIntf::id(*info.vlan_id); 913 if (emitSignal) 914 { 915 this->emit_object_added(); 916 } 917 } 918 919 void EthernetInterface::VlanProperties::delete_() 920 { 921 auto intf = eth.interfaceName(); 922 923 // Remove all configs for the current interface 924 const auto& confDir = eth.manager.getConfDir(); 925 std::error_code ec; 926 std::filesystem::remove(config::pathForIntfConf(confDir, intf), ec); 927 std::filesystem::remove(config::pathForIntfDev(confDir, intf), ec); 928 929 // Write an updated parent interface since it has a VLAN entry 930 for (const auto& [_, intf] : eth.manager.interfaces) 931 { 932 if (intf->ifIdx == parentIdx) 933 { 934 intf->writeConfigurationFile(); 935 } 936 } 937 938 // We need to forcibly delete the interface as systemd does not 939 deleteInterface(intf); 940 941 if (eth.ifIdx > 0) 942 { 943 eth.manager.interfacesByIdx.erase(eth.ifIdx); 944 } 945 eth.manager.interfaces.erase(intf); 946 } 947 948 } // namespace network 949 } // namespace phosphor 950