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