blob: 1c80c1d707f96d76bc11830b30c0f3f0c09e2104 [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:
70 if (data.size() == sizeof(ether_addr))
71 {
72 ret.mac.emplace(stdplus::raw::copyFrom<ether_addr>(data));
73 }
74 break;
75 case IFLA_MTU:
76 ret.mtu.emplace(stdplus::raw::copyFrom<unsigned>(data));
77 break;
78 case IFLA_LINK:
79 ret.parent_idx.emplace(stdplus::raw::copyFrom<unsigned>(data));
80 break;
81 case IFLA_LINKINFO:
82 parseLinkInfo(ret, data);
83 break;
84 }
85 }
86 return ret;
87}
88
William A. Kennington IIIa7344c32022-10-31 14:12:27 -070089template <typename Addr>
90static std::optional<std::tuple<unsigned, InAddrAny>>
91 parse(std::string_view msg)
92{
93 std::optional<unsigned> ifIdx;
94 std::optional<InAddrAny> gw;
95 while (!msg.empty())
96 {
97 auto [hdr, data] = extractRtAttr(msg);
98 switch (hdr.rta_type)
99 {
100 case RTA_OIF:
William A. Kennington III6a923632022-11-06 18:17:33 -0800101 ifIdx.emplace(stdplus::raw::copyFromStrict<int>(data));
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700102 break;
103 case RTA_GATEWAY:
William A. Kennington III6a923632022-11-06 18:17:33 -0800104 gw.emplace(stdplus::raw::copyFromStrict<Addr>(data));
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700105 break;
106 }
107 }
108 if (ifIdx && gw)
109 {
110 return std::make_tuple(*ifIdx, *gw);
111 }
112 return std::nullopt;
113}
114
115std::optional<std::tuple<unsigned, InAddrAny>>
116 gatewayFromRtm(std::string_view msg)
117{
118 const auto& rtm = extractRtData<rtmsg>(msg);
119 if (rtm.rtm_table != RT_TABLE_MAIN || rtm.rtm_dst_len != 0)
120 {
121 return std::nullopt;
122 }
123 switch (rtm.rtm_family)
124 {
125 case AF_INET:
126 return parse<in_addr>(msg);
127 case AF_INET6:
128 return parse<in6_addr>(msg);
129 }
130 return std::nullopt;
131}
132
William A. Kennington III6a923632022-11-06 18:17:33 -0800133AddressInfo addrFromRtm(std::string_view msg)
134{
135 const auto& ifa = extractRtData<ifaddrmsg>(msg);
136
137 AddressInfo ret;
138 ret.ifidx = ifa.ifa_index;
139 ret.flags = ifa.ifa_flags;
140 ret.scope = ifa.ifa_scope;
141 std::optional<InAddrAny> addr;
142 while (!msg.empty())
143 {
144 auto [hdr, data] = extractRtAttr(msg);
145 if (hdr.rta_type == IFA_ADDRESS)
146 {
147 addr.emplace(addrFromBuf(ifa.ifa_family, data));
148 }
149 else if (hdr.rta_type == IFA_FLAGS)
150 {
151 ret.flags = stdplus::raw::copyFromStrict<uint32_t>(data);
152 }
153 }
154 if (!addr)
155 {
156 throw std::runtime_error("Missing address");
157 }
158 ret.ifaddr = {*addr, ifa.ifa_prefixlen};
159 return ret;
160}
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 {
174 ret.mac = stdplus::raw::copyFrom<ether_addr>(data);
175 }
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