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