blob: fd686713aeebc10628a5c1206ccd54ac8ffbbae4 [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;
58 ret.flags = ifinfo.ifi_flags;
59 ret.idx = ifinfo.ifi_index;
60 while (!msg.empty())
61 {
62 auto [hdr, data] = netlink::extractRtAttr(msg);
63 switch (hdr.rta_type)
64 {
65 case IFLA_IFNAME:
66 ret.name.emplace(data.begin(), data.end() - 1);
67 break;
68 case IFLA_ADDRESS:
69 if (data.size() == sizeof(ether_addr))
70 {
71 ret.mac.emplace(stdplus::raw::copyFrom<ether_addr>(data));
72 }
73 break;
74 case IFLA_MTU:
75 ret.mtu.emplace(stdplus::raw::copyFrom<unsigned>(data));
76 break;
77 case IFLA_LINK:
78 ret.parent_idx.emplace(stdplus::raw::copyFrom<unsigned>(data));
79 break;
80 case IFLA_LINKINFO:
81 parseLinkInfo(ret, data);
82 break;
83 }
84 }
85 return ret;
86}
87
William A. Kennington IIIa7344c32022-10-31 14:12:27 -070088template <typename Addr>
89static std::optional<std::tuple<unsigned, InAddrAny>>
90 parse(std::string_view msg)
91{
92 std::optional<unsigned> ifIdx;
93 std::optional<InAddrAny> gw;
94 while (!msg.empty())
95 {
96 auto [hdr, data] = extractRtAttr(msg);
97 switch (hdr.rta_type)
98 {
99 case RTA_OIF:
William A. Kennington III6a923632022-11-06 18:17:33 -0800100 ifIdx.emplace(stdplus::raw::copyFromStrict<int>(data));
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700101 break;
102 case RTA_GATEWAY:
William A. Kennington III6a923632022-11-06 18:17:33 -0800103 gw.emplace(stdplus::raw::copyFromStrict<Addr>(data));
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700104 break;
105 }
106 }
107 if (ifIdx && gw)
108 {
109 return std::make_tuple(*ifIdx, *gw);
110 }
111 return std::nullopt;
112}
113
114std::optional<std::tuple<unsigned, InAddrAny>>
115 gatewayFromRtm(std::string_view msg)
116{
117 const auto& rtm = extractRtData<rtmsg>(msg);
118 if (rtm.rtm_table != RT_TABLE_MAIN || rtm.rtm_dst_len != 0)
119 {
120 return std::nullopt;
121 }
122 switch (rtm.rtm_family)
123 {
124 case AF_INET:
125 return parse<in_addr>(msg);
126 case AF_INET6:
127 return parse<in6_addr>(msg);
128 }
129 return std::nullopt;
130}
131
William A. Kennington III6a923632022-11-06 18:17:33 -0800132AddressInfo addrFromRtm(std::string_view msg)
133{
134 const auto& ifa = extractRtData<ifaddrmsg>(msg);
135
136 AddressInfo ret;
137 ret.ifidx = ifa.ifa_index;
138 ret.flags = ifa.ifa_flags;
139 ret.scope = ifa.ifa_scope;
140 std::optional<InAddrAny> addr;
141 while (!msg.empty())
142 {
143 auto [hdr, data] = extractRtAttr(msg);
144 if (hdr.rta_type == IFA_ADDRESS)
145 {
146 addr.emplace(addrFromBuf(ifa.ifa_family, data));
147 }
148 else if (hdr.rta_type == IFA_FLAGS)
149 {
150 ret.flags = stdplus::raw::copyFromStrict<uint32_t>(data);
151 }
152 }
153 if (!addr)
154 {
155 throw std::runtime_error("Missing address");
156 }
157 ret.ifaddr = {*addr, ifa.ifa_prefixlen};
158 return ret;
159}
160
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800161NeighborInfo neighFromRtm(std::string_view msg)
162{
163 const auto& ndm = netlink::extractRtData<ndmsg>(msg);
164
165 NeighborInfo ret;
166 ret.ifidx = ndm.ndm_ifindex;
167 ret.state = ndm.ndm_state;
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800168 while (!msg.empty())
169 {
170 auto [hdr, data] = netlink::extractRtAttr(msg);
171 if (hdr.rta_type == NDA_LLADDR)
172 {
173 ret.mac = stdplus::raw::copyFrom<ether_addr>(data);
174 }
175 else if (hdr.rta_type == NDA_DST)
176 {
177 ret.addr = addrFromBuf(ndm.ndm_family, data);
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800178 }
179 }
William A. Kennington IIIa8426902022-11-07 15:37:41 -0800180 return ret;
181}
182
William A. Kennington IIIa7344c32022-10-31 14:12:27 -0700183} // namespace phosphor::network::netlink