xref: /openbmc/phosphor-networkd/src/ipaddress.cpp (revision 59e5b91d9784274d1d99b4c10e939c38606efacc)
1 #include "ipaddress.hpp"
2 
3 #include "ethernet_interface.hpp"
4 #include "netlink.hpp"
5 #include "network_manager.hpp"
6 #include "util.hpp"
7 
8 #include <linux/netlink.h>
9 #include <linux/rtnetlink.h>
10 
11 #include <phosphor-logging/elog-errors.hpp>
12 #include <phosphor-logging/log.hpp>
13 #include <stdexcept>
14 #include <stdplus/raw.hpp>
15 #include <string>
16 #include <string_view>
17 #include <vector>
18 #include <xyz/openbmc_project/Common/error.hpp>
19 
20 namespace phosphor
21 {
22 namespace network
23 {
24 
25 std::vector<AddressInfo> getCurrentAddresses(const AddressFilter& filter)
26 {
27     std::vector<AddressInfo> addresses;
28     auto cb = [&filter, &addresses](const nlmsghdr& hdr, std::string_view msg) {
29         detail::parseAddress(filter, hdr, msg, addresses);
30     };
31     ifaddrmsg msg{};
32     msg.ifa_index = filter.interface;
33     netlink::performRequest(NETLINK_ROUTE, RTM_GETADDR, NLM_F_DUMP, msg, cb);
34     return addresses;
35 }
36 
37 using namespace phosphor::logging;
38 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
39 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
40 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
41 
42 static auto makeObjPath(std::string_view root, IfAddr addr)
43 {
44     auto ret = sdbusplus::message::object_path(std::string(root));
45     ret /= std::to_string(addr);
46     return ret;
47 }
48 
49 template <typename T>
50 struct Proto
51 {
52 };
53 
54 template <>
55 struct Proto<in_addr>
56 {
57     static inline constexpr auto value = IP::Protocol::IPv4;
58 };
59 
60 template <>
61 struct Proto<in6_addr>
62 {
63     static inline constexpr auto value = IP::Protocol::IPv6;
64 };
65 
66 IPAddress::IPAddress(sdbusplus::bus_t& bus, std::string_view objRoot,
67                      EthernetInterface& parent, IfAddr addr,
68                      AddressOrigin origin) :
69     IPAddress(bus, makeObjPath(objRoot, addr), parent, addr, origin)
70 {
71 }
72 
73 IPAddress::IPAddress(sdbusplus::bus_t& bus,
74                      sdbusplus::message::object_path objPath,
75                      EthernetInterface& parent, IfAddr addr,
76                      AddressOrigin origin) :
77     IPIfaces(bus, objPath.str.c_str(), IPIfaces::action::defer_emit),
78     parent(parent), objPath(std::move(objPath))
79 {
80     IP::address(std::to_string(addr.getAddr()));
81     IP::prefixLength(addr.getPfx());
82     IP::type(std::visit([](auto v) { return Proto<decltype(v)>::value; },
83                         addr.getAddr()));
84     IP::origin(origin);
85 
86     // Emit deferred signal.
87     emit_object_added();
88 }
89 std::string IPAddress::address(std::string /*ipAddress*/)
90 {
91     elog<NotAllowed>(Reason("Property update is not allowed"));
92 }
93 uint8_t IPAddress::prefixLength(uint8_t /*value*/)
94 {
95     elog<NotAllowed>(Reason("Property update is not allowed"));
96 }
97 std::string IPAddress::gateway(std::string /*gateway*/)
98 {
99     elog<NotAllowed>(Reason("Property update is not allowed"));
100 }
101 IP::Protocol IPAddress::type(IP::Protocol /*type*/)
102 {
103     elog<NotAllowed>(Reason("Property update is not allowed"));
104 }
105 IP::AddressOrigin IPAddress::origin(IP::AddressOrigin /*origin*/)
106 {
107     elog<NotAllowed>(Reason("Property update is not allowed"));
108 }
109 void IPAddress::delete_()
110 {
111     if (origin() != IP::AddressOrigin::Static)
112     {
113         log<level::ERR>("Tried to delete a non-static address"),
114             entry("ADDRESS=%s", address().c_str()),
115             entry("PREFIX=%" PRIu8, prefixLength()),
116             entry("INTERFACE=%s", parent.interfaceName().c_str());
117         elog<InternalFailure>();
118     }
119 
120     std::unique_ptr<IPAddress> ptr;
121     for (auto it = parent.addrs.begin(); it != parent.addrs.end(); ++it)
122     {
123         if (it->second.get() == this)
124         {
125             ptr = std::move(it->second);
126             parent.addrs.erase(it);
127             break;
128         }
129     }
130 
131     parent.writeConfigurationFile();
132     parent.manager.reloadConfigs();
133 }
134 
135 namespace detail
136 {
137 
138 void parseAddress(const AddressFilter& filter, const nlmsghdr& hdr,
139                   std::string_view msg, std::vector<AddressInfo>& addresses)
140 {
141     if (hdr.nlmsg_type != RTM_NEWADDR)
142     {
143         throw std::runtime_error("Not an address msg");
144     }
145     const auto& ifaddr = netlink::extractRtData<ifaddrmsg>(msg);
146 
147     // Filter out addresses we don't care about
148     unsigned ifindex = ifaddr.ifa_index;
149     if (filter.interface != 0 && filter.interface != ifindex)
150     {
151         return;
152     }
153     if (filter.scope && *filter.scope != ifaddr.ifa_scope)
154     {
155         return;
156     }
157 
158     // Build the info about the address we found
159     AddressInfo address;
160     address.interface = ifindex;
161     address.prefix = ifaddr.ifa_prefixlen;
162     address.flags = ifaddr.ifa_flags;
163     address.scope = ifaddr.ifa_scope;
164     bool set_addr = false;
165     while (!msg.empty())
166     {
167         auto [hdr, data] = netlink::extractRtAttr(msg);
168         if (hdr.rta_type == IFA_ADDRESS)
169         {
170             address.address = addrFromBuf(ifaddr.ifa_family, data);
171             set_addr = true;
172         }
173         else if (hdr.rta_type == IFA_FLAGS)
174         {
175             address.flags = stdplus::raw::extract<uint32_t>(data);
176         }
177     }
178     if (!set_addr)
179     {
180         throw std::runtime_error("Missing address");
181     }
182     addresses.push_back(std::move(address));
183 }
184 
185 } // namespace detail
186 } // namespace network
187 } // namespace phosphor
188