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