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