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