1 #include "rtnetlink.hpp"
2
3 #include "netlink.hpp"
4 #include "util.hpp"
5
6 #include <linux/rtnetlink.h>
7
8 namespace phosphor::network::netlink
9 {
10
11 using std::literals::string_view_literals::operator""sv;
12
parseVlanInfo(InterfaceInfo & info,std::string_view msg)13 static 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
parseLinkInfo(InterfaceInfo & info,std::string_view msg)31 static 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
intfFromRtm(std::string_view msg)54 InterfaceInfo intfFromRtm(std::string_view msg)
55 {
56 const auto& ifinfo = netlink::extractRtData<ifinfomsg>(msg);
57 InterfaceInfo ret;
58 ret.type = ifinfo.ifi_type;
59 ret.idx = ifinfo.ifi_index;
60 ret.flags = ifinfo.ifi_flags;
61 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(stdplus::EtherAddr))
71 {
72 ret.mac.emplace(
73 stdplus::raw::copyFrom<stdplus::EtherAddr>(data));
74 }
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
90 template <typename Addr>
91 static std::optional<std::tuple<unsigned, stdplus::InAnyAddr>>
parse(std::string_view msg)92 parse(std::string_view msg)
93 {
94 std::optional<unsigned> ifIdx;
95 std::optional<stdplus::InAnyAddr> gw;
96 while (!msg.empty())
97 {
98 auto [hdr, data] = extractRtAttr(msg);
99 switch (hdr.rta_type)
100 {
101 case RTA_OIF:
102 ifIdx.emplace(stdplus::raw::copyFromStrict<int>(data));
103 break;
104 case RTA_GATEWAY:
105 gw.emplace(stdplus::raw::copyFromStrict<Addr>(data));
106 break;
107 }
108 }
109 if (ifIdx && gw)
110 {
111 return std::make_tuple(*ifIdx, *gw);
112 }
113 return std::nullopt;
114 }
115
116 std::optional<std::tuple<unsigned, stdplus::InAnyAddr>>
gatewayFromRtm(std::string_view msg)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<stdplus::In4Addr>(msg);
128 case AF_INET6:
129 return parse<stdplus::In6Addr>(msg);
130 }
131 return std::nullopt;
132 }
133
addrFromRtm(std::string_view msg)134 AddressInfo addrFromRtm(std::string_view msg)
135 {
136 const auto& ifa = extractRtData<ifaddrmsg>(msg);
137
138 uint32_t flags = ifa.ifa_flags;
139 std::optional<stdplus::InAnyAddr> addr;
140 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 {
149 flags = stdplus::raw::copyFromStrict<uint32_t>(data);
150 }
151 }
152 if (!addr)
153 {
154 throw std::runtime_error("Missing address");
155 }
156 return AddressInfo{.ifidx = ifa.ifa_index,
157 .ifaddr = stdplus::SubnetAny{*addr, ifa.ifa_prefixlen},
158 .scope = ifa.ifa_scope,
159 .flags = flags};
160 }
161
neighFromRtm(std::string_view msg)162 NeighborInfo 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;
169 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<stdplus::EtherAddr>(data);
175 }
176 else if (hdr.rta_type == NDA_DST)
177 {
178 ret.addr = addrFromBuf(ndm.ndm_family, data);
179 }
180 }
181 return ret;
182 }
183
184 } // namespace phosphor::network::netlink
185