xref: /openbmc/phosphor-networkd/src/ipaddress.cpp (revision 4b604171f5bbcfc97db33908f46cfe30cf30e95d)
1 #include "config.h"
2 
3 #include "ipaddress.hpp"
4 
5 #include "ethernet_interface.hpp"
6 #include "netlink.hpp"
7 #include "util.hpp"
8 
9 #include <linux/netlink.h>
10 #include <linux/rtnetlink.h>
11 
12 #include <phosphor-logging/elog-errors.hpp>
13 #include <phosphor-logging/log.hpp>
14 #include <stdexcept>
15 #include <stdplus/raw.hpp>
16 #include <string>
17 #include <string_view>
18 #include <vector>
19 #include <xyz/openbmc_project/Common/error.hpp>
20 
21 namespace phosphor
22 {
23 namespace network
24 {
25 
26 std::vector<AddressInfo> getCurrentAddresses(const AddressFilter& filter)
27 {
28     std::vector<AddressInfo> addresses;
29     auto cb = [&filter, &addresses](const nlmsghdr& hdr, std::string_view msg) {
30         detail::parseAddress(filter, hdr, msg, addresses);
31     };
32     ifaddrmsg msg{};
33     msg.ifa_index = filter.interface;
34     netlink::performRequest(NETLINK_ROUTE, RTM_GETADDR, NLM_F_DUMP, msg, cb);
35     return addresses;
36 }
37 
38 using namespace phosphor::logging;
39 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
40 using NotAllowed = sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
41 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
42 
43 IPAddress::IPAddress(sdbusplus::bus_t& bus, const char* objPath,
44                      EthernetInterface& parent, IP::Protocol type,
45                      const std::string& ipaddress, IP::AddressOrigin origin,
46                      uint8_t prefixLength, const std::string& gateway) :
47     IPIfaces(bus, objPath, IPIfaces::action::defer_emit),
48     parent(parent)
49 {
50 
51     IP::address(ipaddress);
52     IP::prefixLength(prefixLength);
53     IP::gateway(gateway);
54     IP::type(type);
55     IP::origin(origin);
56 
57     // Emit deferred signal.
58     emit_object_added();
59 }
60 std::string IPAddress::address(std::string /*ipAddress*/)
61 {
62     elog<NotAllowed>(Reason("Property update is not allowed"));
63 }
64 uint8_t IPAddress::prefixLength(uint8_t /*value*/)
65 {
66     elog<NotAllowed>(Reason("Property update is not allowed"));
67 }
68 std::string IPAddress::gateway(std::string /*gateway*/)
69 {
70     elog<NotAllowed>(Reason("Property update is not allowed"));
71 }
72 IP::Protocol IPAddress::type(IP::Protocol /*type*/)
73 {
74     elog<NotAllowed>(Reason("Property update is not allowed"));
75 }
76 IP::AddressOrigin IPAddress::origin(IP::AddressOrigin /*origin*/)
77 {
78     elog<NotAllowed>(Reason("Property update is not allowed"));
79 }
80 void IPAddress::delete_()
81 {
82     if (origin() != IP::AddressOrigin::Static)
83     {
84         log<level::ERR>("Tried to delete a non-static address"),
85             entry("ADDRESS=%s", address().c_str()),
86             entry("PREFIX=%" PRIu8, prefixLength()),
87             entry("INTERFACE=%s", parent.interfaceName().c_str());
88         elog<InternalFailure>();
89     }
90 
91     parent.deleteObject(address());
92 }
93 
94 namespace detail
95 {
96 
97 void parseAddress(const AddressFilter& filter, const nlmsghdr& hdr,
98                   std::string_view msg, std::vector<AddressInfo>& addresses)
99 {
100     if (hdr.nlmsg_type != RTM_NEWADDR)
101     {
102         throw std::runtime_error("Not an address msg");
103     }
104     auto ifaddr = stdplus::raw::extract<ifaddrmsg>(msg);
105 
106     // Filter out addresses we don't care about
107     unsigned ifindex = ifaddr.ifa_index;
108     if (filter.interface != 0 && filter.interface != ifindex)
109     {
110         return;
111     }
112     if (filter.scope && *filter.scope != ifaddr.ifa_scope)
113     {
114         return;
115     }
116 
117     // Build the info about the address we found
118     AddressInfo address;
119     address.interface = ifindex;
120     address.prefix = ifaddr.ifa_prefixlen;
121     address.flags = ifaddr.ifa_flags;
122     address.scope = ifaddr.ifa_scope;
123     bool set_addr = false;
124     while (!msg.empty())
125     {
126         auto [hdr, data] = netlink::extractRtAttr(msg);
127         if (hdr.rta_type == IFA_ADDRESS)
128         {
129             address.address = addrFromBuf(ifaddr.ifa_family, data);
130             set_addr = true;
131         }
132         else if (hdr.rta_type == IFA_FLAGS)
133         {
134             address.flags = stdplus::raw::extract<uint32_t>(data);
135         }
136     }
137     if (!set_addr)
138     {
139         throw std::runtime_error("Missing address");
140     }
141     addresses.push_back(std::move(address));
142 }
143 
144 } // namespace detail
145 } // namespace network
146 } // namespace phosphor
147