1 #include "config.h" 2 3 #include "neighbor.hpp" 4 5 #include "ethernet_interface.hpp" 6 #include "netlink.hpp" 7 #include "util.hpp" 8 9 #include <linux/neighbour.h> 10 #include <linux/netlink.h> 11 #include <linux/rtnetlink.h> 12 #include <net/if.h> 13 #include <sys/socket.h> 14 #include <sys/types.h> 15 16 #include <phosphor-logging/elog-errors.hpp> 17 #include <phosphor-logging/elog.hpp> 18 #include <stdexcept> 19 #include <stdplus/raw.hpp> 20 #include <string_view> 21 #include <utility> 22 #include <vector> 23 #include <xyz/openbmc_project/Common/error.hpp> 24 25 namespace phosphor 26 { 27 namespace network 28 { 29 namespace detail 30 { 31 32 void parseNeighbor(const NeighborFilter& filter, const nlmsghdr& hdr, 33 std::string_view msg, std::vector<NeighborInfo>& neighbors) 34 { 35 if (hdr.nlmsg_type != RTM_NEWNEIGH) 36 { 37 throw std::runtime_error("Not a neighbor msg"); 38 } 39 auto ndm = stdplus::raw::extract<ndmsg>(msg); 40 41 // Filter out neighbors we don't care about 42 unsigned ifindex = ndm.ndm_ifindex; 43 if (filter.interface != 0 && filter.interface != ifindex) 44 { 45 return; 46 } 47 if ((ndm.ndm_state & filter.state) == 0) 48 { 49 return; 50 } 51 52 // Build the neighbor info for our valid neighbor 53 NeighborInfo neighbor; 54 neighbor.interface = ifindex; 55 neighbor.state = ndm.ndm_state; 56 bool set_addr = false; 57 while (!msg.empty()) 58 { 59 auto [hdr, data] = netlink::extractRtAttr(msg); 60 if (hdr.rta_type == NDA_LLADDR) 61 { 62 neighbor.mac = stdplus::raw::copyFrom<ether_addr>(data); 63 } 64 else if (hdr.rta_type == NDA_DST) 65 { 66 neighbor.address = addrFromBuf(ndm.ndm_family, data); 67 set_addr = true; 68 } 69 } 70 if (!set_addr) 71 { 72 throw std::runtime_error("Missing address"); 73 } 74 neighbors.push_back(std::move(neighbor)); 75 } 76 77 } // namespace detail 78 79 std::vector<NeighborInfo> getCurrentNeighbors(const NeighborFilter& filter) 80 { 81 std::vector<NeighborInfo> neighbors; 82 auto cb = [&filter, &neighbors](const nlmsghdr& hdr, std::string_view msg) { 83 detail::parseNeighbor(filter, hdr, msg, neighbors); 84 }; 85 ndmsg msg{}; 86 msg.ndm_ifindex = filter.interface; 87 netlink::performRequest(NETLINK_ROUTE, RTM_GETNEIGH, NLM_F_DUMP, msg, cb); 88 return neighbors; 89 } 90 91 Neighbor::Neighbor(sdbusplus::bus_t& bus, const char* objPath, 92 EthernetInterface& parent, const std::string& ipAddress, 93 const std::string& macAddress, State state) : 94 NeighborObj(bus, objPath, NeighborObj::action::defer_emit), 95 parent(parent) 96 { 97 NeighborObj::ipAddress(ipAddress); 98 NeighborObj::macAddress(macAddress); 99 NeighborObj::state(state); 100 101 // Emit deferred signal. 102 emit_object_added(); 103 } 104 105 void Neighbor::delete_() 106 { 107 parent.deleteStaticNeighborObject(ipAddress()); 108 } 109 110 using sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 111 using REASON = 112 phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON; 113 using phosphor::logging::elog; 114 115 std::string Neighbor::ipAddress(std::string /*ipAddress*/) 116 { 117 elog<NotAllowed>(REASON("Property update is not allowed")); 118 } 119 120 std::string Neighbor::macAddress(std::string /*macAddress*/) 121 { 122 elog<NotAllowed>(REASON("Property update is not allowed")); 123 } 124 125 Neighbor::State Neighbor::state(State /*state*/) 126 { 127 elog<NotAllowed>(REASON("Property update is not allowed")); 128 } 129 130 } // namespace network 131 } // namespace phosphor 132