1 #include "transporthandler.hpp" 2 3 #include "app/channel.hpp" 4 #include "ipmid.hpp" 5 #include "net.hpp" 6 #include "utils.hpp" 7 8 #include <arpa/inet.h> 9 #include <host-ipmid/ipmid-api.h> 10 11 #include <chrono> 12 #include <fstream> 13 #include <phosphor-logging/elog-errors.hpp> 14 #include <phosphor-logging/log.hpp> 15 #include <sdbusplus/message/types.hpp> 16 #include <sdbusplus/timer.hpp> 17 #include <string> 18 #include <xyz/openbmc_project/Common/error.hpp> 19 20 #define SYSTEMD_NETWORKD_DBUS 1 21 22 #ifdef SYSTEMD_NETWORKD_DBUS 23 #include <mapper.h> 24 #include <systemd/sd-bus.h> 25 #endif 26 27 #if __has_include(<filesystem>) 28 #include <filesystem> 29 #elif __has_include(<experimental/filesystem>) 30 #include <experimental/filesystem> 31 namespace std 32 { 33 // splice experimental::filesystem into std 34 namespace filesystem = std::experimental::filesystem; 35 } // namespace std 36 #else 37 #error filesystem not available 38 #endif 39 40 extern std::unique_ptr<phosphor::Timer> networkTimer; 41 42 const int SIZE_MAC = 18; // xx:xx:xx:xx:xx:xx 43 constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4"; 44 45 std::map<int, std::unique_ptr<struct ChannelConfig_t>> channelConfig; 46 47 using namespace phosphor::logging; 48 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 49 50 namespace fs = std::filesystem; 51 namespace variant_ns = sdbusplus::message::variant_ns; 52 53 void register_netfn_transport_functions() __attribute__((constructor)); 54 55 struct ChannelConfig_t* getChannelConfig(int channel) 56 { 57 auto item = channelConfig.find(channel); 58 if (item == channelConfig.end()) 59 { 60 channelConfig[channel] = std::make_unique<struct ChannelConfig_t>(); 61 } 62 63 return channelConfig[channel].get(); 64 } 65 66 // Helper Function to get IP Address/NetMask/Gateway/MAC Address from Network 67 // Manager or Cache based on Set-In-Progress State 68 ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t* data, int channel) 69 { 70 ipmi_ret_t rc = IPMI_CC_OK; 71 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 72 73 auto ethdevice = ipmi::network::ChanneltoEthernet(channel); 74 // if ethdevice is an empty string they weren't expecting this channel. 75 if (ethdevice.empty()) 76 { 77 // TODO: return error from getNetworkData() 78 return IPMI_CC_INVALID_FIELD_REQUEST; 79 } 80 auto ethIP = ethdevice + "/" + ipmi::network::IP_TYPE; 81 auto channelConf = getChannelConfig(channel); 82 83 try 84 { 85 switch (lan_param) 86 { 87 case LAN_PARM_IP: 88 { 89 std::string ipaddress; 90 if (channelConf->lan_set_in_progress == SET_COMPLETE) 91 { 92 try 93 { 94 auto ipObjectInfo = 95 ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE, 96 ipmi::network::ROOT, ethIP); 97 98 auto properties = ipmi::getAllDbusProperties( 99 bus, ipObjectInfo.second, ipObjectInfo.first, 100 ipmi::network::IP_INTERFACE); 101 102 ipaddress = 103 variant_ns::get<std::string>(properties["Address"]); 104 } 105 // ignore the exception, as it is a valid condition that 106 // the system is not configured with any IP. 107 catch (InternalFailure& e) 108 { 109 // nothing to do. 110 } 111 } 112 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 113 { 114 ipaddress = channelConf->ipaddr; 115 } 116 117 inet_pton(AF_INET, ipaddress.c_str(), 118 reinterpret_cast<void*>(data)); 119 } 120 break; 121 122 case LAN_PARM_IPSRC: 123 { 124 std::string networkInterfacePath; 125 126 if (channelConf->lan_set_in_progress == SET_COMPLETE) 127 { 128 try 129 { 130 ipmi::ObjectTree ancestorMap; 131 // if the system is having ip object,then 132 // get the IP object. 133 auto ipObject = ipmi::getDbusObject( 134 bus, ipmi::network::IP_INTERFACE, 135 ipmi::network::ROOT, ethIP); 136 137 // Get the parent interface of the IP object. 138 try 139 { 140 ipmi::InterfaceList interfaces; 141 interfaces.emplace_back( 142 ipmi::network::ETHERNET_INTERFACE); 143 144 ancestorMap = ipmi::getAllAncestors( 145 bus, ipObject.first, std::move(interfaces)); 146 } 147 catch (InternalFailure& e) 148 { 149 // if unable to get the parent interface 150 // then commit the error and return. 151 log<level::ERR>( 152 "Unable to get the parent interface", 153 entry("PATH=%s", ipObject.first.c_str()), 154 entry("INTERFACE=%s", 155 ipmi::network::ETHERNET_INTERFACE)); 156 break; 157 } 158 // for an ip object there would be single parent 159 // interface. 160 networkInterfacePath = ancestorMap.begin()->first; 161 } 162 catch (InternalFailure& e) 163 { 164 // if there is no ip configured on the system,then 165 // get the network interface object. 166 auto networkInterfaceObject = ipmi::getDbusObject( 167 bus, ipmi::network::ETHERNET_INTERFACE, 168 ipmi::network::ROOT, ethdevice); 169 170 networkInterfacePath = networkInterfaceObject.first; 171 } 172 173 auto variant = ipmi::getDbusProperty( 174 bus, ipmi::network::SERVICE, networkInterfacePath, 175 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled"); 176 177 auto dhcpEnabled = variant_ns::get<bool>(variant); 178 // As per IPMI spec 2=>DHCP, 1=STATIC 179 auto ipsrc = dhcpEnabled ? ipmi::network::IPOrigin::DHCP 180 : ipmi::network::IPOrigin::STATIC; 181 182 std::memcpy(data, &ipsrc, ipmi::network::IPSRC_SIZE_BYTE); 183 } 184 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 185 { 186 std::memcpy(data, &(channelConf->ipsrc), 187 ipmi::network::IPSRC_SIZE_BYTE); 188 } 189 } 190 break; 191 192 case LAN_PARM_SUBNET: 193 { 194 unsigned long mask{}; 195 if (channelConf->lan_set_in_progress == SET_COMPLETE) 196 { 197 try 198 { 199 auto ipObjectInfo = ipmi::getIPObject( 200 bus, ipmi::network::IP_INTERFACE, 201 ipmi::network::ROOT, ipmi::network::IP_TYPE); 202 203 auto properties = ipmi::getAllDbusProperties( 204 bus, ipObjectInfo.second, ipObjectInfo.first, 205 ipmi::network::IP_INTERFACE); 206 207 auto prefix = variant_ns::get<uint8_t>( 208 properties["PrefixLength"]); 209 mask = ipmi::network::MASK_32_BIT; 210 mask = htonl(mask << (ipmi::network::BITS_32 - prefix)); 211 } 212 // ignore the exception, as it is a valid condition that 213 // the system is not configured with any IP. 214 catch (InternalFailure& e) 215 { 216 // nothing to do 217 } 218 std::memcpy(data, &mask, 219 ipmi::network::IPV4_ADDRESS_SIZE_BYTE); 220 } 221 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 222 { 223 inet_pton(AF_INET, channelConf->netmask.c_str(), 224 reinterpret_cast<void*>(data)); 225 } 226 } 227 break; 228 229 case LAN_PARM_GATEWAY: 230 { 231 std::string gateway; 232 233 if (channelConf->lan_set_in_progress == SET_COMPLETE) 234 { 235 try 236 { 237 auto systemObject = ipmi::getDbusObject( 238 bus, ipmi::network::SYSTEMCONFIG_INTERFACE, 239 ipmi::network::ROOT); 240 241 auto systemProperties = ipmi::getAllDbusProperties( 242 bus, systemObject.second, systemObject.first, 243 ipmi::network::SYSTEMCONFIG_INTERFACE); 244 245 gateway = variant_ns::get<std::string>( 246 systemProperties["DefaultGateway"]); 247 } 248 // ignore the exception, as it is a valid condition that 249 // the system is not configured with any IP. 250 catch (InternalFailure& e) 251 { 252 // nothing to do 253 } 254 } 255 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 256 { 257 gateway = channelConf->gateway; 258 } 259 260 inet_pton(AF_INET, gateway.c_str(), 261 reinterpret_cast<void*>(data)); 262 } 263 break; 264 265 case LAN_PARM_MAC: 266 { 267 std::string macAddress; 268 if (channelConf->lan_set_in_progress == SET_COMPLETE) 269 { 270 auto macObjectInfo = 271 ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE, 272 ipmi::network::ROOT, ethdevice); 273 274 auto variant = ipmi::getDbusProperty( 275 bus, macObjectInfo.second, macObjectInfo.first, 276 ipmi::network::MAC_INTERFACE, "MACAddress"); 277 278 macAddress = variant_ns::get<std::string>(variant); 279 } 280 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 281 { 282 macAddress = channelConf->macAddress; 283 } 284 285 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, 286 (data), (data + 1), (data + 2), (data + 3), (data + 4), 287 (data + 5)); 288 } 289 break; 290 291 case LAN_PARM_VLAN: 292 { 293 uint16_t vlanID{}; 294 if (channelConf->lan_set_in_progress == SET_COMPLETE) 295 { 296 try 297 { 298 auto ipObjectInfo = ipmi::getIPObject( 299 bus, ipmi::network::IP_INTERFACE, 300 ipmi::network::ROOT, ipmi::network::IP_TYPE); 301 302 vlanID = static_cast<uint16_t>( 303 ipmi::network::getVLAN(ipObjectInfo.first)); 304 305 vlanID = htole16(vlanID); 306 307 if (vlanID) 308 { 309 // Enable the 16th bit 310 vlanID |= htole16(ipmi::network::VLAN_ENABLE_MASK); 311 } 312 } 313 // ignore the exception, as it is a valid condition that 314 // the system is not configured with any IP. 315 catch (InternalFailure& e) 316 { 317 // nothing to do 318 } 319 320 std::memcpy(data, &vlanID, ipmi::network::VLAN_SIZE_BYTE); 321 } 322 else if (channelConf->lan_set_in_progress == SET_IN_PROGRESS) 323 { 324 std::memcpy(data, &(channelConf->vlanID), 325 ipmi::network::VLAN_SIZE_BYTE); 326 } 327 } 328 break; 329 330 default: 331 rc = IPMI_CC_PARM_OUT_OF_RANGE; 332 } 333 } 334 catch (InternalFailure& e) 335 { 336 commit<InternalFailure>(); 337 rc = IPMI_CC_UNSPECIFIED_ERROR; 338 return rc; 339 } 340 return rc; 341 } 342 343 namespace cipher 344 { 345 346 std::vector<uint8_t> getCipherList() 347 { 348 std::vector<uint8_t> cipherList; 349 350 std::ifstream jsonFile(configFile); 351 if (!jsonFile.is_open()) 352 { 353 log<level::ERR>("Channel Cipher suites file not found"); 354 elog<InternalFailure>(); 355 } 356 357 auto data = Json::parse(jsonFile, nullptr, false); 358 if (data.is_discarded()) 359 { 360 log<level::ERR>("Parsing channel cipher suites JSON failed"); 361 elog<InternalFailure>(); 362 } 363 364 // Byte 1 is reserved 365 cipherList.push_back(0x00); 366 367 for (const auto& record : data) 368 { 369 cipherList.push_back(record.value(cipher, 0)); 370 } 371 372 return cipherList; 373 } 374 375 } // namespace cipher 376 377 ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 378 ipmi_request_t request, 379 ipmi_response_t response, 380 ipmi_data_len_t data_len, 381 ipmi_context_t context) 382 { 383 // Status code. 384 ipmi_ret_t rc = IPMI_CC_INVALID; 385 *data_len = 0; 386 return rc; 387 } 388 389 struct set_lan_t 390 { 391 uint8_t channel; 392 uint8_t parameter; 393 uint8_t data[8]; // Per IPMI spec, not expecting more than this size 394 } __attribute__((packed)); 395 396 ipmi_ret_t ipmi_transport_set_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 397 ipmi_request_t request, 398 ipmi_response_t response, 399 ipmi_data_len_t data_len, 400 ipmi_context_t context) 401 { 402 ipmi_ret_t rc = IPMI_CC_OK; 403 *data_len = 0; 404 405 using namespace std::chrono_literals; 406 407 // time to wait before applying the network changes. 408 constexpr auto networkTimeout = 10000000us; // 10 sec 409 410 char ipaddr[INET_ADDRSTRLEN]; 411 char netmask[INET_ADDRSTRLEN]; 412 char gateway[INET_ADDRSTRLEN]; 413 414 auto reqptr = reinterpret_cast<const set_lan_t*>(request); 415 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 416 417 // channel number is the lower nibble 418 int channel = reqptr->channel & CHANNEL_MASK; 419 auto ethdevice = ipmi::network::ChanneltoEthernet(channel); 420 if (ethdevice.empty()) 421 { 422 return IPMI_CC_INVALID_FIELD_REQUEST; 423 } 424 auto channelConf = getChannelConfig(channel); 425 426 switch (reqptr->parameter) 427 { 428 case LAN_PARM_IP: 429 { 430 std::snprintf(ipaddr, INET_ADDRSTRLEN, 431 ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], 432 reqptr->data[1], reqptr->data[2], reqptr->data[3]); 433 434 channelConf->ipaddr.assign(ipaddr); 435 } 436 break; 437 438 case LAN_PARM_IPSRC: 439 { 440 uint8_t ipsrc{}; 441 std::memcpy(&ipsrc, reqptr->data, ipmi::network::IPSRC_SIZE_BYTE); 442 channelConf->ipsrc = static_cast<ipmi::network::IPOrigin>(ipsrc); 443 } 444 break; 445 446 case LAN_PARM_MAC: 447 { 448 char mac[SIZE_MAC]; 449 450 std::snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT, 451 reqptr->data[0], reqptr->data[1], reqptr->data[2], 452 reqptr->data[3], reqptr->data[4], reqptr->data[5]); 453 454 auto macObjectInfo = 455 ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE, 456 ipmi::network::ROOT, ethdevice); 457 458 ipmi::setDbusProperty( 459 bus, macObjectInfo.second, macObjectInfo.first, 460 ipmi::network::MAC_INTERFACE, "MACAddress", std::string(mac)); 461 462 channelConf->macAddress = mac; 463 } 464 break; 465 466 case LAN_PARM_SUBNET: 467 { 468 std::snprintf(netmask, INET_ADDRSTRLEN, 469 ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], 470 reqptr->data[1], reqptr->data[2], reqptr->data[3]); 471 channelConf->netmask.assign(netmask); 472 } 473 break; 474 475 case LAN_PARM_GATEWAY: 476 { 477 std::snprintf(gateway, INET_ADDRSTRLEN, 478 ipmi::network::IP_ADDRESS_FORMAT, reqptr->data[0], 479 reqptr->data[1], reqptr->data[2], reqptr->data[3]); 480 channelConf->gateway.assign(gateway); 481 } 482 break; 483 484 case LAN_PARM_VLAN: 485 { 486 uint16_t vlan{}; 487 std::memcpy(&vlan, reqptr->data, ipmi::network::VLAN_SIZE_BYTE); 488 // We are not storing the enable bit 489 // We assume that ipmitool always send enable 490 // bit as 1. 491 vlan = le16toh(vlan); 492 channelConf->vlanID = vlan; 493 } 494 break; 495 496 case LAN_PARM_INPROGRESS: 497 { 498 if (reqptr->data[0] == SET_COMPLETE) 499 { 500 channelConf->lan_set_in_progress = SET_COMPLETE; 501 502 log<level::INFO>( 503 "Network data from Cache", 504 entry("PREFIX=%s", channelConf->netmask.c_str()), 505 entry("ADDRESS=%s", channelConf->ipaddr.c_str()), 506 entry("GATEWAY=%s", channelConf->gateway.c_str()), 507 entry("VLAN=%d", channelConf->vlanID)); 508 509 if (!networkTimer) 510 { 511 log<level::ERR>("Network timer is not instantiated"); 512 return IPMI_CC_UNSPECIFIED_ERROR; 513 } 514 515 // start/restart the timer 516 networkTimer->start(networkTimeout); 517 } 518 else if (reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress 519 { 520 channelConf->lan_set_in_progress = SET_IN_PROGRESS; 521 channelConf->flush = true; 522 } 523 } 524 break; 525 526 default: 527 { 528 rc = IPMI_CC_PARM_NOT_SUPPORTED; 529 } 530 } 531 532 return rc; 533 } 534 535 struct get_lan_t 536 { 537 uint8_t rev_channel; 538 uint8_t parameter; 539 uint8_t parameter_set; 540 uint8_t parameter_block; 541 } __attribute__((packed)); 542 543 ipmi_ret_t ipmi_transport_get_lan(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 544 ipmi_request_t request, 545 ipmi_response_t response, 546 ipmi_data_len_t data_len, 547 ipmi_context_t context) 548 { 549 ipmi_ret_t rc = IPMI_CC_OK; 550 *data_len = 0; 551 const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0 552 553 get_lan_t* reqptr = (get_lan_t*)request; 554 // channel number is the lower nibble 555 int channel = reqptr->rev_channel & CHANNEL_MASK; 556 557 if (reqptr->rev_channel & 0x80) // Revision is bit 7 558 { 559 // Only current revision was requested 560 *data_len = sizeof(current_revision); 561 std::memcpy(response, ¤t_revision, *data_len); 562 return IPMI_CC_OK; 563 } 564 565 static std::vector<uint8_t> cipherList; 566 static auto listInit = false; 567 568 if (!listInit) 569 { 570 try 571 { 572 cipherList = cipher::getCipherList(); 573 listInit = true; 574 } 575 catch (const std::exception& e) 576 { 577 return IPMI_CC_UNSPECIFIED_ERROR; 578 } 579 } 580 581 auto ethdevice = ipmi::network::ChanneltoEthernet(channel); 582 if (ethdevice.empty()) 583 { 584 return IPMI_CC_INVALID_FIELD_REQUEST; 585 } 586 auto channelConf = getChannelConfig(channel); 587 588 if (reqptr->parameter == LAN_PARM_INPROGRESS) 589 { 590 uint8_t buf[] = {current_revision, channelConf->lan_set_in_progress}; 591 *data_len = sizeof(buf); 592 std::memcpy(response, &buf, *data_len); 593 } 594 else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT) 595 { 596 uint8_t buf[] = {current_revision, 0x04}; 597 *data_len = sizeof(buf); 598 std::memcpy(response, &buf, *data_len); 599 } 600 else if (reqptr->parameter == LAN_PARM_AUTHENABLES) 601 { 602 uint8_t buf[] = {current_revision, 0x04, 0x04, 0x04, 0x04, 0x04}; 603 *data_len = sizeof(buf); 604 std::memcpy(response, &buf, *data_len); 605 } 606 else if ((reqptr->parameter == LAN_PARM_IP) || 607 (reqptr->parameter == LAN_PARM_SUBNET) || 608 (reqptr->parameter == LAN_PARM_GATEWAY) || 609 (reqptr->parameter == LAN_PARM_MAC)) 610 { 611 uint8_t buf[ipmi::network::MAC_ADDRESS_SIZE_BYTE + 1] = {}; 612 613 *data_len = sizeof(current_revision); 614 std::memcpy(buf, ¤t_revision, *data_len); 615 616 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK) 617 { 618 if (reqptr->parameter == LAN_PARM_MAC) 619 { 620 *data_len = sizeof(buf); 621 } 622 else 623 { 624 *data_len = ipmi::network::IPV4_ADDRESS_SIZE_BYTE + 1; 625 } 626 std::memcpy(response, &buf, *data_len); 627 } 628 else 629 { 630 rc = IPMI_CC_UNSPECIFIED_ERROR; 631 } 632 } 633 else if (reqptr->parameter == LAN_PARM_VLAN) 634 { 635 uint8_t buf[ipmi::network::VLAN_SIZE_BYTE + 1] = {}; 636 637 *data_len = sizeof(current_revision); 638 std::memcpy(buf, ¤t_revision, *data_len); 639 if (getNetworkData(reqptr->parameter, &buf[1], channel) == IPMI_CC_OK) 640 { 641 *data_len = sizeof(buf); 642 std::memcpy(response, &buf, *data_len); 643 } 644 } 645 else if (reqptr->parameter == LAN_PARM_IPSRC) 646 { 647 uint8_t buff[ipmi::network::IPSRC_SIZE_BYTE + 1] = {}; 648 *data_len = sizeof(current_revision); 649 std::memcpy(buff, ¤t_revision, *data_len); 650 if (getNetworkData(reqptr->parameter, &buff[1], channel) == IPMI_CC_OK) 651 { 652 *data_len = sizeof(buff); 653 std::memcpy(response, &buff, *data_len); 654 } 655 } 656 else if (reqptr->parameter == CIPHER_SUITE_COUNT) 657 { 658 *(static_cast<uint8_t*>(response)) = current_revision; 659 // Byte 1 is reserved byte and does not indicate a cipher suite ID, so 660 // no of cipher suite entry count is one less than the size of the 661 // vector 662 auto count = static_cast<uint8_t>(cipherList.size() - 1); 663 *(static_cast<uint8_t*>(response) + 1) = count; 664 *data_len = sizeof(current_revision) + sizeof(count); 665 } 666 else if (reqptr->parameter == CIPHER_SUITE_ENTRIES) 667 { 668 *(static_cast<uint8_t*>(response)) = current_revision; 669 // Byte 1 is reserved 670 std::copy_n(cipherList.data(), cipherList.size(), 671 static_cast<uint8_t*>(response) + 1); 672 *data_len = 673 sizeof(current_revision) + static_cast<uint8_t>(cipherList.size()); 674 } 675 else 676 { 677 log<level::ERR>("Unsupported parameter", 678 entry("PARAMETER=0x%x", reqptr->parameter)); 679 rc = IPMI_CC_PARM_NOT_SUPPORTED; 680 } 681 682 return rc; 683 } 684 685 void applyChanges(int channel) 686 { 687 std::string ipaddress; 688 std::string gateway; 689 uint8_t prefix{}; 690 uint32_t vlanID{}; 691 std::string networkInterfacePath; 692 ipmi::DbusObjectInfo ipObject; 693 ipmi::DbusObjectInfo systemObject; 694 695 auto ethdevice = ipmi::network::ChanneltoEthernet(channel); 696 if (ethdevice.empty()) 697 { 698 log<level::ERR>("Unable to get the interface name", 699 entry("CHANNEL=%d", channel)); 700 return; 701 } 702 auto ethIp = ethdevice + "/" + ipmi::network::IP_TYPE; 703 auto channelConf = getChannelConfig(channel); 704 705 try 706 { 707 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 708 709 log<level::INFO>("Network data from Cache", 710 entry("PREFIX=%s", channelConf->netmask.c_str()), 711 entry("ADDRESS=%s", channelConf->ipaddr.c_str()), 712 entry("GATEWAY=%s", channelConf->gateway.c_str()), 713 entry("VLAN=%d", channelConf->vlanID), 714 entry("IPSRC=%d", channelConf->ipsrc)); 715 if (channelConf->vlanID != ipmi::network::VLAN_ID_MASK) 716 { 717 // get the first twelve bits which is vlan id 718 // not interested in rest of the bits. 719 channelConf->vlanID = le32toh(channelConf->vlanID); 720 vlanID = channelConf->vlanID & ipmi::network::VLAN_ID_MASK; 721 } 722 723 // if the asked ip src is DHCP then not interested in 724 // any given data except vlan. 725 if (channelConf->ipsrc != ipmi::network::IPOrigin::DHCP) 726 { 727 // always get the system object 728 systemObject = 729 ipmi::getDbusObject(bus, ipmi::network::SYSTEMCONFIG_INTERFACE, 730 ipmi::network::ROOT); 731 732 // the below code is to determine the mode of the interface 733 // as the handling is same, if the system is configured with 734 // DHCP or user has given all the data. 735 try 736 { 737 ipmi::ObjectTree ancestorMap; 738 739 ipmi::InterfaceList interfaces{ 740 ipmi::network::ETHERNET_INTERFACE}; 741 742 // if the system is having ip object,then 743 // get the IP object. 744 ipObject = ipmi::getIPObject(bus, ipmi::network::IP_INTERFACE, 745 ipmi::network::ROOT, ethIp); 746 747 // Get the parent interface of the IP object. 748 try 749 { 750 ancestorMap = ipmi::getAllAncestors(bus, ipObject.first, 751 std::move(interfaces)); 752 } 753 catch (InternalFailure& e) 754 { 755 // if unable to get the parent interface 756 // then commit the error and return. 757 log<level::ERR>("Unable to get the parent interface", 758 entry("PATH=%s", ipObject.first.c_str()), 759 entry("INTERFACE=%s", 760 ipmi::network::ETHERNET_INTERFACE)); 761 commit<InternalFailure>(); 762 channelConf->clear(); 763 return; 764 } 765 766 networkInterfacePath = ancestorMap.begin()->first; 767 } 768 catch (InternalFailure& e) 769 { 770 // TODO Currently IPMI supports single interface,need to handle 771 // Multiple interface through 772 // https://github.com/openbmc/openbmc/issues/2138 773 774 // if there is no ip configured on the system,then 775 // get the network interface object. 776 auto networkInterfaceObject = 777 ipmi::getDbusObject(bus, ipmi::network::ETHERNET_INTERFACE, 778 ipmi::network::ROOT, ethdevice); 779 780 networkInterfacePath = std::move(networkInterfaceObject.first); 781 } 782 783 // get the configured mode on the system. 784 auto enableDHCP = variant_ns::get<bool>(ipmi::getDbusProperty( 785 bus, ipmi::network::SERVICE, networkInterfacePath, 786 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled")); 787 788 // if ip address source is not given then get the ip source mode 789 // from the system so that it can be applied later. 790 if (channelConf->ipsrc == ipmi::network::IPOrigin::UNSPECIFIED) 791 { 792 channelConf->ipsrc = (enableDHCP) 793 ? ipmi::network::IPOrigin::DHCP 794 : ipmi::network::IPOrigin::STATIC; 795 } 796 797 // check whether user has given all the data 798 // or the configured system interface is dhcp enabled, 799 // in both of the cases get the values from the cache. 800 if ((!channelConf->ipaddr.empty() && 801 !channelConf->netmask.empty() && 802 !channelConf->gateway.empty()) || 803 (enableDHCP)) // configured system interface mode = DHCP 804 { 805 // convert mask into prefix 806 ipaddress = channelConf->ipaddr; 807 prefix = ipmi::network::toPrefix(AF_INET, channelConf->netmask); 808 gateway = channelConf->gateway; 809 } 810 else // asked ip src = static and configured system src = static 811 // or partially given data. 812 { 813 // We have partial filled cache so get the remaining 814 // info from the system. 815 816 // Get the network data from the system as user has 817 // not given all the data then use the data fetched from the 818 // system but it is implementation dependent,IPMI spec doesn't 819 // force it. 820 821 // if system is not having any ip object don't throw error, 822 try 823 { 824 auto properties = ipmi::getAllDbusProperties( 825 bus, ipObject.second, ipObject.first, 826 ipmi::network::IP_INTERFACE); 827 828 ipaddress = channelConf->ipaddr.empty() 829 ? variant_ns::get<std::string>( 830 properties["Address"]) 831 : channelConf->ipaddr; 832 833 prefix = channelConf->netmask.empty() 834 ? variant_ns::get<uint8_t>( 835 properties["PrefixLength"]) 836 : ipmi::network::toPrefix( 837 AF_INET, channelConf->netmask); 838 } 839 catch (InternalFailure& e) 840 { 841 log<level::INFO>( 842 "Failed to get IP object which matches", 843 entry("INTERFACE=%s", ipmi::network::IP_INTERFACE), 844 entry("MATCH=%s", ethIp.c_str())); 845 } 846 847 auto systemProperties = ipmi::getAllDbusProperties( 848 bus, systemObject.second, systemObject.first, 849 ipmi::network::SYSTEMCONFIG_INTERFACE); 850 851 gateway = channelConf->gateway.empty() 852 ? variant_ns::get<std::string>( 853 systemProperties["DefaultGateway"]) 854 : channelConf->gateway; 855 } 856 } 857 858 // Currently network manager doesn't support purging of all the 859 // ip addresses and the vlan interfaces from the parent interface, 860 // TODO once the support is there, will make the change here. 861 // https://github.com/openbmc/openbmc/issues/2141. 862 863 // TODO Currently IPMI supports single interface,need to handle 864 // Multiple interface through 865 // https://github.com/openbmc/openbmc/issues/2138 866 867 // instead of deleting all the vlan interfaces and 868 // all the ipv4 address,we will call reset method. 869 // delete all the vlan interfaces 870 871 ipmi::deleteAllDbusObjects(bus, ipmi::network::ROOT, 872 ipmi::network::VLAN_INTERFACE); 873 874 // set the interface mode to static 875 auto networkInterfaceObject = 876 ipmi::getDbusObject(bus, ipmi::network::ETHERNET_INTERFACE, 877 ipmi::network::ROOT, ethdevice); 878 879 // setting the physical interface mode to static. 880 ipmi::setDbusProperty( 881 bus, ipmi::network::SERVICE, networkInterfaceObject.first, 882 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled", false); 883 884 networkInterfacePath = networkInterfaceObject.first; 885 886 // delete all the ipv4 addresses 887 ipmi::deleteAllDbusObjects(bus, ipmi::network::ROOT, 888 ipmi::network::IP_INTERFACE, ethIp); 889 890 if (vlanID) 891 { 892 ipmi::network::createVLAN(bus, ipmi::network::SERVICE, 893 ipmi::network::ROOT, ethdevice, vlanID); 894 895 auto networkInterfaceObject = ipmi::getDbusObject( 896 bus, ipmi::network::VLAN_INTERFACE, ipmi::network::ROOT); 897 898 networkInterfacePath = networkInterfaceObject.first; 899 } 900 901 if (channelConf->ipsrc == ipmi::network::IPOrigin::DHCP) 902 { 903 ipmi::setDbusProperty( 904 bus, ipmi::network::SERVICE, networkInterfacePath, 905 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled", true); 906 } 907 else 908 { 909 // change the mode to static 910 ipmi::setDbusProperty( 911 bus, ipmi::network::SERVICE, networkInterfacePath, 912 ipmi::network::ETHERNET_INTERFACE, "DHCPEnabled", false); 913 914 if (!ipaddress.empty()) 915 { 916 ipmi::network::createIP(bus, ipmi::network::SERVICE, 917 networkInterfacePath, ipv4Protocol, 918 ipaddress, prefix); 919 } 920 921 if (!gateway.empty()) 922 { 923 ipmi::setDbusProperty(bus, systemObject.second, 924 systemObject.first, 925 ipmi::network::SYSTEMCONFIG_INTERFACE, 926 "DefaultGateway", std::string(gateway)); 927 } 928 } 929 } 930 catch (InternalFailure& e) 931 { 932 log<level::ERR>( 933 "Failed to set network data", entry("PREFIX=%d", prefix), 934 entry("ADDRESS=%s", ipaddress.c_str()), 935 entry("GATEWAY=%s", gateway.c_str()), entry("VLANID=%d", vlanID), 936 entry("IPSRC=%d", channelConf->ipsrc)); 937 938 commit<InternalFailure>(); 939 } 940 941 channelConf->clear(); 942 } 943 944 void commitNetworkChanges() 945 { 946 for (const auto& channel : channelConfig) 947 { 948 if (channel.second->flush) 949 { 950 applyChanges(channel.first); 951 } 952 } 953 } 954 955 void createNetworkTimer() 956 { 957 if (!networkTimer) 958 { 959 std::function<void()> networkTimerCallback( 960 std::bind(&commitNetworkChanges)); 961 962 networkTimer = std::make_unique<phosphor::Timer>(networkTimerCallback); 963 } 964 } 965 966 void register_netfn_transport_functions() 967 { 968 // As this timer is only for transport handler 969 // so creating it here. 970 createNetworkTimer(); 971 // <Wildcard Command> 972 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_WILDCARD, NULL, 973 ipmi_transport_wildcard, PRIVILEGE_USER); 974 975 // <Set LAN Configuration Parameters> 976 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_SET_LAN, NULL, 977 ipmi_transport_set_lan, PRIVILEGE_ADMIN); 978 979 // <Get LAN Configuration Parameters> 980 ipmi_register_callback(NETFUN_TRANSPORT, IPMI_CMD_GET_LAN, NULL, 981 ipmi_transport_get_lan, PRIVILEGE_OPERATOR); 982 983 return; 984 } 985