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