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