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