blob: 5229c94c9ef1a4a5b46a384b8215aa4846deec6f [file] [log] [blame]
William A. Kennington IIIa7344c32022-10-31 14:12:27 -07001#include "rtnetlink.hpp"
2
3#include "netlink.hpp"
William A. Kennington III6a923632022-11-06 18:17:33 -08004#include "util.hpp"
William A. Kennington IIIa7344c32022-10-31 14:12:27 -07005
6#include <linux/rtnetlink.h>
7
8namespace phosphor::network::netlink
9{
10
William A. Kennington III1aeacc92022-11-13 18:26:45 -080011using std::literals::string_view_literals::operator""sv;
12
13static void parseVlanInfo(InterfaceInfo& info, std::string_view msg)
14{
15 if (msg.data() == nullptr)
16 {
17 throw std::runtime_error("Missing VLAN data");
18 }
19 while (!msg.empty())
20 {
21 auto [hdr, data] = netlink::extractRtAttr(msg);
22 switch (hdr.rta_type)
23 {
24 case IFLA_VLAN_ID:
25 info.vlan_id.emplace(stdplus::raw::copyFrom<uint16_t>(data));
26 break;
27 }
28 }
29}
30
31static void parseLinkInfo(InterfaceInfo& info, std::string_view msg)
32{
33 std::string_view submsg;
34 while (!msg.empty())
35 {
36 auto [hdr, data] = netlink::extractRtAttr(msg);
37 switch (hdr.rta_type)
38 {
39 case IFLA_INFO_KIND:
40 data.remove_suffix(1);
41 info.kind.emplace(data);
42 break;
43 case IFLA_INFO_DATA:
44 submsg = data;
45 break;
46 }
47 }
48 if (info.kind == "vlan"sv)
49 {
50 parseVlanInfo(info, submsg);
51 }
52}
53
54InterfaceInfo intfFromRtm(std::string_view msg)
55{
56 const auto& ifinfo = netlink::extractRtData<ifinfomsg>(msg);
57 InterfaceInfo ret;
William A. Kennington III9c441fd2023-02-24 13:40:01 -080058 ret.type = ifinfo.ifi_type;
William A. Kennington III1aeacc92022-11-13 18:26:45 -080059 ret.idx = ifinfo.ifi_index;
William A. Kennington III9c441fd2023-02-24 13:40:01 -080060 ret.flags = ifinfo.ifi_flags;
William A. Kennington III1aeacc92022-11-13 18:26:45 -080061 while (!msg.empty())
62 {
63 auto [hdr, data] = netlink::extractRtAttr(msg);
64 switch (hdr.rta_type)
65 {
66 case IFLA_IFNAME:
67 ret.name.emplace(data.begin(), data.end() - 1);
68 break;
69 case IFLA_ADDRESS:
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -070070 if (data.size() == sizeof(stdplus::EtherAddr))
William A. Kennington III1aeacc92022-11-13 18:26:45 -080071 {
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -070072 ret.mac.emplace(
73 stdplus::raw::copyFrom<stdplus::EtherAddr>(data));
William A. Kennington III1aeacc92022-11-13 18:26:45 -080074 }
75 break;
76 case IFLA_MTU:
77 ret.mtu.emplace(stdplus::raw::copyFrom<unsigned>(data));
78 break;
79 case IFLA_LINK:
80 ret.parent_idx.emplace(stdplus::raw::copyFrom<unsigned>(data));
81 break;
82 case IFLA_LINKINFO:
83 parseLinkInfo(ret, data);
84 break;
85 }
86 }
87 return ret;
88}
89
William A. Kennington IIIa7344c32022-10-31 14:12:27 -070090template <typename Addr>
William A. Kennington III9b2a20d2023-06-17 14:05:48 -070091static std::optional<std::tuple<unsigned, stdplus::InAnyAddr>>
William A. Kennington IIIa7344c32022-10-31 14:12:27 -070092 parse(std::string_view msg)
93{
94 std::optional<unsigned> ifIdx;
William A. Kennington III9b2a20d2023-06-17 14:05:48 -070095 std::optional<stdplus::InAnyAddr> gw;
William A. Kennington IIIa7344c32022-10-31 14:12:27 -070096 while (!msg.empty())
97 {
98 auto [hdr, data] = extractRtAttr(msg);
99 switch (hdr.rta_type)
100 {
101 case RTA_OIF:
William A. Kennington III6a923632022-11-06 18:17:33 -0800102 ifIdx.emplace(stdplus::raw::copyFromStrict<int>(data));
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700103 break;
104 case RTA_GATEWAY:
William A. Kennington III6a923632022-11-06 18:17:33 -0800105 gw.emplace(stdplus::raw::copyFromStrict<Addr>(data));
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700106 break;
107 }
108 }
109 if (ifIdx && gw)
110 {
111 return std::make_tuple(*ifIdx, *gw);
112 }
113 return std::nullopt;
114}
115
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700116std::optional<std::tuple<unsigned, stdplus::InAnyAddr>>
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700117 gatewayFromRtm(std::string_view msg)
118{
119 const auto& rtm = extractRtData<rtmsg>(msg);
120 if (rtm.rtm_table != RT_TABLE_MAIN || rtm.rtm_dst_len != 0)
121 {
122 return std::nullopt;
123 }
124 switch (rtm.rtm_family)
125 {
126 case AF_INET:
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700127 return parse<stdplus::In4Addr>(msg);
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700128 case AF_INET6:
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700129 return parse<stdplus::In6Addr>(msg);
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700130 }
131 return std::nullopt;
132}
133
William A. Kennington III6a923632022-11-06 18:17:33 -0800134AddressInfo addrFromRtm(std::string_view msg)
135{
136 const auto& ifa = extractRtData<ifaddrmsg>(msg);
137
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700138 uint32_t flags = ifa.ifa_flags;
139 std::optional<stdplus::InAnyAddr> addr;
William A. Kennington III6a923632022-11-06 18:17:33 -0800140 while (!msg.empty())
141 {
142 auto [hdr, data] = extractRtAttr(msg);
143 if (hdr.rta_type == IFA_ADDRESS)
144 {
145 addr.emplace(addrFromBuf(ifa.ifa_family, data));
146 }
147 else if (hdr.rta_type == IFA_FLAGS)
148 {
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700149 flags = stdplus::raw::copyFromStrict<uint32_t>(data);
William A. Kennington III6a923632022-11-06 18:17:33 -0800150 }
151 }
152 if (!addr)
153 {
154 throw std::runtime_error("Missing address");
155 }
William A. Kennington III9b2a20d2023-06-17 14:05:48 -0700156 return AddressInfo{.ifidx = ifa.ifa_index,
157 .ifaddr = stdplus::SubnetAny{*addr, ifa.ifa_prefixlen},
158 .scope = ifa.ifa_scope,
159 .flags = flags};
William A. Kennington III6a923632022-11-06 18:17:33 -0800160}
161
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800162NeighborInfo neighFromRtm(std::string_view msg)
163{
164 const auto& ndm = netlink::extractRtData<ndmsg>(msg);
165
166 NeighborInfo ret;
167 ret.ifidx = ndm.ndm_ifindex;
168 ret.state = ndm.ndm_state;
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800169 while (!msg.empty())
170 {
171 auto [hdr, data] = netlink::extractRtAttr(msg);
172 if (hdr.rta_type == NDA_LLADDR)
173 {
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700174 ret.mac = stdplus::raw::copyFrom<stdplus::EtherAddr>(data);
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800175 }
176 else if (hdr.rta_type == NDA_DST)
177 {
178 ret.addr = addrFromBuf(ndm.ndm_family, data);
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800179 }
180 }
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800181 return ret;
182}
183
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700184} // namespace phosphor::network::netlink