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