blob: 4308d2310eb845135f7add94e4b659da01188efa [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>
91static std::optional<std::tuple<unsigned, InAddrAny>>
92 parse(std::string_view msg)
93{
94 std::optional<unsigned> ifIdx;
95 std::optional<InAddrAny> gw;
96 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
116std::optional<std::tuple<unsigned, InAddrAny>>
117 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:
127 return parse<in_addr>(msg);
128 case AF_INET6:
129 return parse<in6_addr>(msg);
130 }
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
138 AddressInfo ret;
139 ret.ifidx = ifa.ifa_index;
140 ret.flags = ifa.ifa_flags;
141 ret.scope = ifa.ifa_scope;
142 std::optional<InAddrAny> addr;
143 while (!msg.empty())
144 {
145 auto [hdr, data] = extractRtAttr(msg);
146 if (hdr.rta_type == IFA_ADDRESS)
147 {
148 addr.emplace(addrFromBuf(ifa.ifa_family, data));
149 }
150 else if (hdr.rta_type == IFA_FLAGS)
151 {
152 ret.flags = stdplus::raw::copyFromStrict<uint32_t>(data);
153 }
154 }
155 if (!addr)
156 {
157 throw std::runtime_error("Missing address");
158 }
159 ret.ifaddr = {*addr, ifa.ifa_prefixlen};
160 return ret;
161}
162
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800163NeighborInfo neighFromRtm(std::string_view msg)
164{
165 const auto& ndm = netlink::extractRtData<ndmsg>(msg);
166
167 NeighborInfo ret;
168 ret.ifidx = ndm.ndm_ifindex;
169 ret.state = ndm.ndm_state;
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800170 while (!msg.empty())
171 {
172 auto [hdr, data] = netlink::extractRtAttr(msg);
173 if (hdr.rta_type == NDA_LLADDR)
174 {
William A. Kennington IIIb7d6a1a2023-06-17 02:00:53 -0700175 ret.mac = stdplus::raw::copyFrom<stdplus::EtherAddr>(data);
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800176 }
177 else if (hdr.rta_type == NDA_DST)
178 {
179 ret.addr = addrFromBuf(ndm.ndm_family, data);
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800180 }
181 }
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800182 return ret;
183}
184
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700185} // namespace phosphor::network::netlink