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