1 #include "neighbor.hpp" 2 3 #include "ethernet_interface.hpp" 4 #include "netlink.hpp" 5 #include "network_manager.hpp" 6 #include "util.hpp" 7 8 #include <linux/neighbour.h> 9 #include <linux/netlink.h> 10 #include <linux/rtnetlink.h> 11 #include <net/if.h> 12 #include <sys/socket.h> 13 #include <sys/types.h> 14 15 #include <phosphor-logging/elog-errors.hpp> 16 #include <phosphor-logging/elog.hpp> 17 #include <stdexcept> 18 #include <stdplus/raw.hpp> 19 #include <string> 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 const auto& ndm = netlink::extractRtData<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 static auto makeObjPath(std::string_view root, InAddrAny addr) 92 { 93 auto ret = sdbusplus::message::object_path(std::string(root)); 94 ret /= std::to_string(addr); 95 return ret; 96 } 97 98 Neighbor::Neighbor(sdbusplus::bus_t& bus, std::string_view objRoot, 99 EthernetInterface& parent, InAddrAny addr, ether_addr lladdr, 100 State state) : 101 Neighbor(bus, makeObjPath(objRoot, addr), parent, addr, lladdr, state) 102 { 103 } 104 105 Neighbor::Neighbor(sdbusplus::bus_t& bus, 106 sdbusplus::message::object_path objPath, 107 EthernetInterface& parent, InAddrAny addr, ether_addr lladdr, 108 State state) : 109 NeighborObj(bus, objPath.str.c_str(), NeighborObj::action::defer_emit), 110 parent(parent), objPath(std::move(objPath)) 111 { 112 NeighborObj::ipAddress(std::to_string(addr)); 113 NeighborObj::macAddress(std::to_string(lladdr)); 114 NeighborObj::state(state); 115 116 // Emit deferred signal. 117 emit_object_added(); 118 } 119 120 void Neighbor::delete_() 121 { 122 auto& neighbors = parent.staticNeighbors; 123 std::unique_ptr<Neighbor> ptr; 124 for (auto it = neighbors.begin(); it != neighbors.end(); ++it) 125 { 126 if (it->second.get() == this) 127 { 128 ptr = std::move(it->second); 129 neighbors.erase(it); 130 break; 131 } 132 } 133 134 parent.writeConfigurationFile(); 135 parent.manager.reloadConfigs(); 136 } 137 138 using sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed; 139 using REASON = 140 phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON; 141 using phosphor::logging::elog; 142 143 std::string Neighbor::ipAddress(std::string /*ipAddress*/) 144 { 145 elog<NotAllowed>(REASON("Property update is not allowed")); 146 } 147 148 std::string Neighbor::macAddress(std::string /*macAddress*/) 149 { 150 elog<NotAllowed>(REASON("Property update is not allowed")); 151 } 152 153 Neighbor::State Neighbor::state(State /*state*/) 154 { 155 elog<NotAllowed>(REASON("Property update is not allowed")); 156 } 157 158 } // namespace network 159 } // namespace phosphor 160