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