From 4bbc3db633003d19bea34874e4274e701b8e3741 Mon Sep 17 00:00:00 2001 From: "William A. Kennington III" Date: Mon, 15 Apr 2019 00:02:10 -0700 Subject: transporthandler: Support Gateway MAC Adds support for setting the MAC address of the gateway. Most of the interesting code in this change is around saving / restoring the gateway MAC address when the gateway or interface change. Change-Id: I85b7c665c44af4f030f51456be355f3eb11ab2fc Signed-off-by: William A. Kennington III --- transporthandler.cpp | 197 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 182 insertions(+), 15 deletions(-) diff --git a/transporthandler.cpp b/transporthandler.cpp index b48cbd0..777171c 100644 --- a/transporthandler.cpp +++ b/transporthandler.cpp @@ -31,6 +31,7 @@ #include #include #include +#include using phosphor::logging::commit; using phosphor::logging::elog; @@ -39,6 +40,7 @@ using phosphor::logging::level; using phosphor::logging::log; using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; using sdbusplus::xyz::openbmc_project::Network::server::IP; +using sdbusplus::xyz::openbmc_project::Network::server::Neighbor; namespace cipher { @@ -97,6 +99,9 @@ constexpr auto INTF_ETHERNET = "xyz.openbmc_project.Network.EthernetInterface"; constexpr auto INTF_IP = "xyz.openbmc_project.Network.IP"; constexpr auto INTF_IP_CREATE = "xyz.openbmc_project.Network.IP.Create"; constexpr auto INTF_MAC = "xyz.openbmc_project.Network.MACAddress"; +constexpr auto INTF_NEIGHBOR = "xyz.openbmc_project.Network.Neighbor"; +constexpr auto INTF_NEIGHBOR_CREATE_STATIC = + "xyz.openbmc_project.Network.Neighbor.CreateStatic"; constexpr auto INTF_VLAN = "xyz.openbmc_project.Network.VLAN"; constexpr auto INTF_VLAN_CREATE = "xyz.openbmc_project.Network.VLAN.Create"; @@ -133,6 +138,15 @@ struct IfAddr uint8_t prefix; }; +/** @brief Interface Neighbor configuration parameters */ +template +struct IfNeigh +{ + std::string path; + typename AddrFamily::addr ip; + ether_addr mac; +}; + /** @brief IPMI LAN Parameters */ enum class LanParam : uint8_t { @@ -144,6 +158,7 @@ enum class LanParam : uint8_t MAC = 5, SubnetMask = 6, Gateway1 = 12, + Gateway1MAC = 13, VLANId = 20, CiphersuiteSupport = 22, CiphersuiteEntries = 23, @@ -167,6 +182,19 @@ enum class SetStatus : uint8_t Commit = 2, }; +/** @brief A trivial helper used to determine if two PODs are equal + * + * @params[in] a - The first object to compare + * @params[in] b - The second object to compare + * @return True if the objects are the same bytewise + */ +template +bool equal(const T& a, const T& b) +{ + static_assert(std::is_trivially_copyable_v); + return std::memcmp(&a, &b, sizeof(T)) == 0; +} + /** @brief Copies bytes from an array into a trivially copyable container * * @params[out] t - The container receiving the data @@ -485,21 +513,6 @@ std::optional::addr> return stringToAddr(gatewayStr.c_str()); } -/** @brief Sets the system wide value for the default gateway - * - * @param[in] bus - The bus object used for lookups - * @param[in] params - The parameters for the channel - * @param[in] gateway - Gateway address to apply - */ -template -void setGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params, - const typename AddrFamily::addr& address) -{ - setDbusProperty(bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG, - AddrFamily::propertyGateway, - addrToString(address)); -} - /** @brief A lazy lookup mechanism for iterating over object properties stored * in DBus. This will only perform the object lookup when needed, and * retains a cache of previous lookups to speed up future iterations. @@ -747,6 +760,131 @@ void reconfigureIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params, prefix.value_or(fallbackPrefix)); } +template +std::optional> + findStaticNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params, + const typename AddrFamily::addr& ip, + ObjectLookupCache& neighbors) +{ + const auto state = + sdbusplus::xyz::openbmc_project::Network::server::convertForMessage( + Neighbor::State::Permanent); + for (const auto& [path, neighbor] : neighbors) + { + const auto& ipStr = std::get(neighbor.at("IPAddress")); + auto neighIP = maybeStringToAddr(ipStr.c_str()); + if (!neighIP) + { + continue; + } + if (!equal(*neighIP, ip)) + { + continue; + } + if (state != std::get(neighbor.at("State"))) + { + continue; + } + + IfNeigh ret; + ret.path = path; + ret.ip = ip; + const auto& macStr = std::get(neighbor.at("MACAddress")); + ret.mac = stringToMAC(macStr.c_str()); + return std::move(ret); + } + + return std::nullopt; +} + +template +void createNeighbor(sdbusplus::bus::bus& bus, const ChannelParams& params, + const typename AddrFamily::addr& address, + const ether_addr& mac) +{ + auto newreq = + bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(), + INTF_NEIGHBOR_CREATE_STATIC, "Neighbor"); + std::string macStr = ether_ntoa(&mac); + newreq.append(addrToString(address), macStr); + bus.call_noreply(newreq); +} + +/** @brief Sets the system wide value for the default gateway + * + * @param[in] bus - The bus object used for lookups + * @param[in] params - The parameters for the channel + * @param[in] gateway - Gateway address to apply + */ +template +void setGatewayProperty(sdbusplus::bus::bus& bus, const ChannelParams& params, + const typename AddrFamily::addr& address) +{ + // Save the old gateway MAC address if it exists so we can recreate it + auto gateway = getGatewayProperty(bus, params); + std::optional> neighbor; + if (gateway) + { + ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); + neighbor = findStaticNeighbor(bus, params, *gateway, neighbors); + } + + setDbusProperty(bus, params.service, PATH_SYSTEMCONFIG, INTF_SYSTEMCONFIG, + AddrFamily::propertyGateway, + addrToString(address)); + + // Restore the gateway MAC if we had one + if (neighbor) + { + deleteObjectIfExists(bus, params.service, neighbor->path); + createNeighbor(bus, params, address, neighbor->mac); + } +} + +template +std::optional> findGatewayNeighbor(sdbusplus::bus::bus& bus, + const ChannelParams& params, + ObjectLookupCache& neighbors) +{ + auto gateway = getGatewayProperty(bus, params); + if (!gateway) + { + return std::nullopt; + } + + return findStaticNeighbor(bus, params, *gateway, neighbors); +} + +template +std::optional> getGatewayNeighbor(sdbusplus::bus::bus& bus, + const ChannelParams& params) +{ + ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); + return findGatewayNeighbor(bus, params, neighbors); +} + +template +void reconfigureGatewayMAC(sdbusplus::bus::bus& bus, + const ChannelParams& params, const ether_addr& mac) +{ + auto gateway = getGatewayProperty(bus, params); + if (!gateway) + { + log("Tried to set Gateway MAC without Gateway"); + elog(); + } + + ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); + auto neighbor = + findStaticNeighbor(bus, params, *gateway, neighbors); + if (neighbor) + { + deleteObjectIfExists(bus, params.service, neighbor->path); + } + + createNeighbor(bus, params, *gateway, mac); +} + /** @brief Gets the vlan ID configured on the interface * * @param[in] bus - The bus object used for lookups @@ -847,6 +985,8 @@ void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, ObjectLookupCache ips(bus, params, INTF_IP); auto ifaddr4 = findIfAddr(bus, params, 0, originsV4, ips); auto dhcp = getDHCPProperty(bus, params); + ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR); + auto neighbor4 = findGatewayNeighbor(bus, params, neighbors); deconfigureChannel(bus, params); createVLAN(bus, params, vlan); @@ -857,6 +997,10 @@ void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, { createIfAddr(bus, params, ifaddr4->address, ifaddr4->prefix); } + if (neighbor4) + { + createNeighbor(bus, params, neighbor4->ip, neighbor4->mac); + } } /** @brief Turns a prefix into a netmask @@ -1055,6 +1199,18 @@ RspType<> setLan(uint4_t channelBits, uint4_t, uint8_t parameter, channelCall>(channel, gateway); return responseSuccess(); } + case LanParam::Gateway1MAC: + { + ether_addr gatewayMAC; + std::array bytes; + if (req.unpack(bytes) != 0 || !req.fullyUnpacked()) + { + return responseReqDataLenInvalid(); + } + copyInto(gatewayMAC, bytes); + channelCall>(channel, gatewayMAC); + return responseSuccess(); + } case LanParam::VLANId: { uint16_t vlanData; @@ -1193,6 +1349,17 @@ RspType getLan(uint4_t channelBits, uint3_t, bool revOnly, ret.pack(dataRef(gateway)); return responseSuccess(std::move(ret)); } + case LanParam::Gateway1MAC: + { + ether_addr mac{}; + auto neighbor = channelCall>(channel); + if (neighbor) + { + mac = neighbor->mac; + } + ret.pack(dataRef(mac)); + return responseSuccess(std::move(ret)); + } case LanParam::VLANId: { uint16_t vlan = channelCall(channel); -- cgit v1.2.1