1 #include "ipaddress.hpp" 2 3 #include "ethernet_interface.hpp" 4 #include "netlink.hpp" 5 #include "network_manager.hpp" 6 #include "util.hpp" 7 8 #include <linux/netlink.h> 9 #include <linux/rtnetlink.h> 10 11 #include <phosphor-logging/elog-errors.hpp> 12 #include <phosphor-logging/log.hpp> 13 #include <stdexcept> 14 #include <stdplus/raw.hpp> 15 #include <string> 16 #include <string_view> 17 #include <vector> 18 #include <xyz/openbmc_project/Common/error.hpp> 19 20 namespace phosphor 21 { 22 namespace network 23 { 24 25 std::vector<AddressInfo> getCurrentAddresses(const AddressFilter& filter) 26 { 27 std::vector<AddressInfo> addresses; 28 auto cb = [&filter, &addresses](const nlmsghdr& hdr, std::string_view msg) { 29 detail::parseAddress(filter, hdr, msg, addresses); 30 }; 31 ifaddrmsg msg{}; 32 msg.ifa_index = filter.interface; 33 netlink::performRequest(NETLINK_ROUTE, RTM_GETADDR, NLM_F_DUMP, msg, cb); 34 return addresses; 35 } 36 37 using namespace phosphor::logging; 38 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 39 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 40 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON; 41 42 static auto makeObjPath(std::string_view root, IfAddr addr) 43 { 44 auto ret = sdbusplus::message::object_path(std::string(root)); 45 ret /= std::to_string(addr); 46 return ret; 47 } 48 49 template <typename T> 50 struct Proto 51 { 52 }; 53 54 template <> 55 struct Proto<in_addr> 56 { 57 static inline constexpr auto value = IP::Protocol::IPv4; 58 }; 59 60 template <> 61 struct Proto<in6_addr> 62 { 63 static inline constexpr auto value = IP::Protocol::IPv6; 64 }; 65 66 IPAddress::IPAddress(sdbusplus::bus_t& bus, std::string_view objRoot, 67 EthernetInterface& parent, IfAddr addr, 68 AddressOrigin origin) : 69 IPAddress(bus, makeObjPath(objRoot, addr), parent, addr, origin) 70 { 71 } 72 73 IPAddress::IPAddress(sdbusplus::bus_t& bus, 74 sdbusplus::message::object_path objPath, 75 EthernetInterface& parent, IfAddr addr, 76 AddressOrigin origin) : 77 IPIfaces(bus, objPath.str.c_str(), IPIfaces::action::defer_emit), 78 parent(parent), objPath(std::move(objPath)) 79 { 80 IP::address(std::to_string(addr.getAddr())); 81 IP::prefixLength(addr.getPfx()); 82 IP::type(std::visit([](auto v) { return Proto<decltype(v)>::value; }, 83 addr.getAddr())); 84 IP::origin(origin); 85 86 // Emit deferred signal. 87 emit_object_added(); 88 } 89 std::string IPAddress::address(std::string /*ipAddress*/) 90 { 91 elog<NotAllowed>(Reason("Property update is not allowed")); 92 } 93 uint8_t IPAddress::prefixLength(uint8_t /*value*/) 94 { 95 elog<NotAllowed>(Reason("Property update is not allowed")); 96 } 97 std::string IPAddress::gateway(std::string /*gateway*/) 98 { 99 elog<NotAllowed>(Reason("Property update is not allowed")); 100 } 101 IP::Protocol IPAddress::type(IP::Protocol /*type*/) 102 { 103 elog<NotAllowed>(Reason("Property update is not allowed")); 104 } 105 IP::AddressOrigin IPAddress::origin(IP::AddressOrigin /*origin*/) 106 { 107 elog<NotAllowed>(Reason("Property update is not allowed")); 108 } 109 void IPAddress::delete_() 110 { 111 if (origin() != IP::AddressOrigin::Static) 112 { 113 log<level::ERR>("Tried to delete a non-static address"), 114 entry("ADDRESS=%s", address().c_str()), 115 entry("PREFIX=%" PRIu8, prefixLength()), 116 entry("INTERFACE=%s", parent.interfaceName().c_str()); 117 elog<InternalFailure>(); 118 } 119 120 std::unique_ptr<IPAddress> ptr; 121 for (auto it = parent.addrs.begin(); it != parent.addrs.end(); ++it) 122 { 123 if (it->second.get() == this) 124 { 125 ptr = std::move(it->second); 126 parent.addrs.erase(it); 127 break; 128 } 129 } 130 131 parent.writeConfigurationFile(); 132 parent.manager.reloadConfigs(); 133 } 134 135 namespace detail 136 { 137 138 void parseAddress(const AddressFilter& filter, const nlmsghdr& hdr, 139 std::string_view msg, std::vector<AddressInfo>& addresses) 140 { 141 if (hdr.nlmsg_type != RTM_NEWADDR) 142 { 143 throw std::runtime_error("Not an address msg"); 144 } 145 const auto& ifaddr = netlink::extractRtData<ifaddrmsg>(msg); 146 147 // Filter out addresses we don't care about 148 unsigned ifindex = ifaddr.ifa_index; 149 if (filter.interface != 0 && filter.interface != ifindex) 150 { 151 return; 152 } 153 if (filter.scope && *filter.scope != ifaddr.ifa_scope) 154 { 155 return; 156 } 157 158 // Build the info about the address we found 159 AddressInfo address; 160 address.interface = ifindex; 161 address.prefix = ifaddr.ifa_prefixlen; 162 address.flags = ifaddr.ifa_flags; 163 address.scope = ifaddr.ifa_scope; 164 bool set_addr = false; 165 while (!msg.empty()) 166 { 167 auto [hdr, data] = netlink::extractRtAttr(msg); 168 if (hdr.rta_type == IFA_ADDRESS) 169 { 170 address.address = addrFromBuf(ifaddr.ifa_family, data); 171 set_addr = true; 172 } 173 else if (hdr.rta_type == IFA_FLAGS) 174 { 175 address.flags = stdplus::raw::extract<uint32_t>(data); 176 } 177 } 178 if (!set_addr) 179 { 180 throw std::runtime_error("Missing address"); 181 } 182 addresses.push_back(std::move(address)); 183 } 184 185 } // namespace detail 186 } // namespace network 187 } // namespace phosphor 188