xref: /openbmc/phosphor-networkd/src/rtnetlink.cpp (revision 9b2a20d3cfa1131521456b9ebfde7a7bb8b234bb)
1a7344c3aSWilliam A. Kennington III #include "rtnetlink.hpp"
2a7344c3aSWilliam A. Kennington III 
3a7344c3aSWilliam A. Kennington III #include "netlink.hpp"
46a92363eSWilliam A. Kennington III #include "util.hpp"
5a7344c3aSWilliam A. Kennington III 
6a7344c3aSWilliam A. Kennington III #include <linux/rtnetlink.h>
7a7344c3aSWilliam A. Kennington III 
8a7344c3aSWilliam A. Kennington III namespace phosphor::network::netlink
9a7344c3aSWilliam A. Kennington III {
10a7344c3aSWilliam A. Kennington III 
111aeacc90SWilliam A. Kennington III using std::literals::string_view_literals::operator""sv;
121aeacc90SWilliam A. Kennington III 
parseVlanInfo(InterfaceInfo & info,std::string_view msg)131aeacc90SWilliam A. Kennington III static void parseVlanInfo(InterfaceInfo& info, std::string_view msg)
141aeacc90SWilliam A. Kennington III {
151aeacc90SWilliam A. Kennington III     if (msg.data() == nullptr)
161aeacc90SWilliam A. Kennington III     {
171aeacc90SWilliam A. Kennington III         throw std::runtime_error("Missing VLAN data");
181aeacc90SWilliam A. Kennington III     }
191aeacc90SWilliam A. Kennington III     while (!msg.empty())
201aeacc90SWilliam A. Kennington III     {
211aeacc90SWilliam A. Kennington III         auto [hdr, data] = netlink::extractRtAttr(msg);
221aeacc90SWilliam A. Kennington III         switch (hdr.rta_type)
231aeacc90SWilliam A. Kennington III         {
241aeacc90SWilliam A. Kennington III             case IFLA_VLAN_ID:
251aeacc90SWilliam A. Kennington III                 info.vlan_id.emplace(stdplus::raw::copyFrom<uint16_t>(data));
261aeacc90SWilliam A. Kennington III                 break;
271aeacc90SWilliam A. Kennington III         }
281aeacc90SWilliam A. Kennington III     }
291aeacc90SWilliam A. Kennington III }
301aeacc90SWilliam A. Kennington III 
parseLinkInfo(InterfaceInfo & info,std::string_view msg)311aeacc90SWilliam A. Kennington III static void parseLinkInfo(InterfaceInfo& info, std::string_view msg)
321aeacc90SWilliam A. Kennington III {
331aeacc90SWilliam A. Kennington III     std::string_view submsg;
341aeacc90SWilliam A. Kennington III     while (!msg.empty())
351aeacc90SWilliam A. Kennington III     {
361aeacc90SWilliam A. Kennington III         auto [hdr, data] = netlink::extractRtAttr(msg);
371aeacc90SWilliam A. Kennington III         switch (hdr.rta_type)
381aeacc90SWilliam A. Kennington III         {
391aeacc90SWilliam A. Kennington III             case IFLA_INFO_KIND:
401aeacc90SWilliam A. Kennington III                 data.remove_suffix(1);
411aeacc90SWilliam A. Kennington III                 info.kind.emplace(data);
421aeacc90SWilliam A. Kennington III                 break;
431aeacc90SWilliam A. Kennington III             case IFLA_INFO_DATA:
441aeacc90SWilliam A. Kennington III                 submsg = data;
451aeacc90SWilliam A. Kennington III                 break;
461aeacc90SWilliam A. Kennington III         }
471aeacc90SWilliam A. Kennington III     }
481aeacc90SWilliam A. Kennington III     if (info.kind == "vlan"sv)
491aeacc90SWilliam A. Kennington III     {
501aeacc90SWilliam A. Kennington III         parseVlanInfo(info, submsg);
511aeacc90SWilliam A. Kennington III     }
521aeacc90SWilliam A. Kennington III }
531aeacc90SWilliam A. Kennington III 
intfFromRtm(std::string_view msg)541aeacc90SWilliam A. Kennington III InterfaceInfo intfFromRtm(std::string_view msg)
551aeacc90SWilliam A. Kennington III {
561aeacc90SWilliam A. Kennington III     const auto& ifinfo = netlink::extractRtData<ifinfomsg>(msg);
571aeacc90SWilliam A. Kennington III     InterfaceInfo ret;
589c441fd4SWilliam A. Kennington III     ret.type = ifinfo.ifi_type;
591aeacc90SWilliam A. Kennington III     ret.idx = ifinfo.ifi_index;
609c441fd4SWilliam A. Kennington III     ret.flags = ifinfo.ifi_flags;
611aeacc90SWilliam A. Kennington III     while (!msg.empty())
621aeacc90SWilliam A. Kennington III     {
631aeacc90SWilliam A. Kennington III         auto [hdr, data] = netlink::extractRtAttr(msg);
641aeacc90SWilliam A. Kennington III         switch (hdr.rta_type)
651aeacc90SWilliam A. Kennington III         {
661aeacc90SWilliam A. Kennington III             case IFLA_IFNAME:
671aeacc90SWilliam A. Kennington III                 ret.name.emplace(data.begin(), data.end() - 1);
681aeacc90SWilliam A. Kennington III                 break;
691aeacc90SWilliam A. Kennington III             case IFLA_ADDRESS:
70b7d6a1a7SWilliam A. Kennington III                 if (data.size() == sizeof(stdplus::EtherAddr))
711aeacc90SWilliam A. Kennington III                 {
72b7d6a1a7SWilliam A. Kennington III                     ret.mac.emplace(
73b7d6a1a7SWilliam A. Kennington III                         stdplus::raw::copyFrom<stdplus::EtherAddr>(data));
741aeacc90SWilliam A. Kennington III                 }
751aeacc90SWilliam A. Kennington III                 break;
761aeacc90SWilliam A. Kennington III             case IFLA_MTU:
771aeacc90SWilliam A. Kennington III                 ret.mtu.emplace(stdplus::raw::copyFrom<unsigned>(data));
781aeacc90SWilliam A. Kennington III                 break;
791aeacc90SWilliam A. Kennington III             case IFLA_LINK:
801aeacc90SWilliam A. Kennington III                 ret.parent_idx.emplace(stdplus::raw::copyFrom<unsigned>(data));
811aeacc90SWilliam A. Kennington III                 break;
821aeacc90SWilliam A. Kennington III             case IFLA_LINKINFO:
831aeacc90SWilliam A. Kennington III                 parseLinkInfo(ret, data);
841aeacc90SWilliam A. Kennington III                 break;
851aeacc90SWilliam A. Kennington III         }
861aeacc90SWilliam A. Kennington III     }
871aeacc90SWilliam A. Kennington III     return ret;
881aeacc90SWilliam A. Kennington III }
891aeacc90SWilliam A. Kennington III 
90a7344c3aSWilliam A. Kennington III template <typename Addr>
91*9b2a20d3SWilliam A. Kennington III static std::optional<std::tuple<unsigned, stdplus::InAnyAddr>>
parse(std::string_view msg)92a7344c3aSWilliam A. Kennington III     parse(std::string_view msg)
93a7344c3aSWilliam A. Kennington III {
94a7344c3aSWilliam A. Kennington III     std::optional<unsigned> ifIdx;
95*9b2a20d3SWilliam A. Kennington III     std::optional<stdplus::InAnyAddr> gw;
96a7344c3aSWilliam A. Kennington III     while (!msg.empty())
97a7344c3aSWilliam A. Kennington III     {
98a7344c3aSWilliam A. Kennington III         auto [hdr, data] = extractRtAttr(msg);
99a7344c3aSWilliam A. Kennington III         switch (hdr.rta_type)
100a7344c3aSWilliam A. Kennington III         {
101a7344c3aSWilliam A. Kennington III             case RTA_OIF:
1026a92363eSWilliam A. Kennington III                 ifIdx.emplace(stdplus::raw::copyFromStrict<int>(data));
103a7344c3aSWilliam A. Kennington III                 break;
104a7344c3aSWilliam A. Kennington III             case RTA_GATEWAY:
1056a92363eSWilliam A. Kennington III                 gw.emplace(stdplus::raw::copyFromStrict<Addr>(data));
106a7344c3aSWilliam A. Kennington III                 break;
107a7344c3aSWilliam A. Kennington III         }
108a7344c3aSWilliam A. Kennington III     }
109a7344c3aSWilliam A. Kennington III     if (ifIdx && gw)
110a7344c3aSWilliam A. Kennington III     {
111a7344c3aSWilliam A. Kennington III         return std::make_tuple(*ifIdx, *gw);
112a7344c3aSWilliam A. Kennington III     }
113a7344c3aSWilliam A. Kennington III     return std::nullopt;
114a7344c3aSWilliam A. Kennington III }
115a7344c3aSWilliam A. Kennington III 
116*9b2a20d3SWilliam A. Kennington III std::optional<std::tuple<unsigned, stdplus::InAnyAddr>>
gatewayFromRtm(std::string_view msg)117a7344c3aSWilliam A. Kennington III     gatewayFromRtm(std::string_view msg)
118a7344c3aSWilliam A. Kennington III {
119a7344c3aSWilliam A. Kennington III     const auto& rtm = extractRtData<rtmsg>(msg);
120a7344c3aSWilliam A. Kennington III     if (rtm.rtm_table != RT_TABLE_MAIN || rtm.rtm_dst_len != 0)
121a7344c3aSWilliam A. Kennington III     {
122a7344c3aSWilliam A. Kennington III         return std::nullopt;
123a7344c3aSWilliam A. Kennington III     }
124a7344c3aSWilliam A. Kennington III     switch (rtm.rtm_family)
125a7344c3aSWilliam A. Kennington III     {
126a7344c3aSWilliam A. Kennington III         case AF_INET:
127*9b2a20d3SWilliam A. Kennington III             return parse<stdplus::In4Addr>(msg);
128a7344c3aSWilliam A. Kennington III         case AF_INET6:
129*9b2a20d3SWilliam A. Kennington III             return parse<stdplus::In6Addr>(msg);
130a7344c3aSWilliam A. Kennington III     }
131a7344c3aSWilliam A. Kennington III     return std::nullopt;
132a7344c3aSWilliam A. Kennington III }
133a7344c3aSWilliam A. Kennington III 
addrFromRtm(std::string_view msg)1346a92363eSWilliam A. Kennington III AddressInfo addrFromRtm(std::string_view msg)
1356a92363eSWilliam A. Kennington III {
1366a92363eSWilliam A. Kennington III     const auto& ifa = extractRtData<ifaddrmsg>(msg);
1376a92363eSWilliam A. Kennington III 
138*9b2a20d3SWilliam A. Kennington III     uint32_t flags = ifa.ifa_flags;
139*9b2a20d3SWilliam A. Kennington III     std::optional<stdplus::InAnyAddr> addr;
1406a92363eSWilliam A. Kennington III     while (!msg.empty())
1416a92363eSWilliam A. Kennington III     {
1426a92363eSWilliam A. Kennington III         auto [hdr, data] = extractRtAttr(msg);
1436a92363eSWilliam A. Kennington III         if (hdr.rta_type == IFA_ADDRESS)
1446a92363eSWilliam A. Kennington III         {
1456a92363eSWilliam A. Kennington III             addr.emplace(addrFromBuf(ifa.ifa_family, data));
1466a92363eSWilliam A. Kennington III         }
1476a92363eSWilliam A. Kennington III         else if (hdr.rta_type == IFA_FLAGS)
1486a92363eSWilliam A. Kennington III         {
149*9b2a20d3SWilliam A. Kennington III             flags = stdplus::raw::copyFromStrict<uint32_t>(data);
1506a92363eSWilliam A. Kennington III         }
1516a92363eSWilliam A. Kennington III     }
1526a92363eSWilliam A. Kennington III     if (!addr)
1536a92363eSWilliam A. Kennington III     {
1546a92363eSWilliam A. Kennington III         throw std::runtime_error("Missing address");
1556a92363eSWilliam A. Kennington III     }
156*9b2a20d3SWilliam A. Kennington III     return AddressInfo{.ifidx = ifa.ifa_index,
157*9b2a20d3SWilliam A. Kennington III                        .ifaddr = stdplus::SubnetAny{*addr, ifa.ifa_prefixlen},
158*9b2a20d3SWilliam A. Kennington III                        .scope = ifa.ifa_scope,
159*9b2a20d3SWilliam A. Kennington III                        .flags = flags};
1606a92363eSWilliam A. Kennington III }
1616a92363eSWilliam A. Kennington III 
neighFromRtm(std::string_view msg)162a8426902SWilliam A. Kennington III NeighborInfo neighFromRtm(std::string_view msg)
163a8426902SWilliam A. Kennington III {
164a8426902SWilliam A. Kennington III     const auto& ndm = netlink::extractRtData<ndmsg>(msg);
165a8426902SWilliam A. Kennington III 
166a8426902SWilliam A. Kennington III     NeighborInfo ret;
167a8426902SWilliam A. Kennington III     ret.ifidx = ndm.ndm_ifindex;
168a8426902SWilliam A. Kennington III     ret.state = ndm.ndm_state;
169a8426902SWilliam A. Kennington III     while (!msg.empty())
170a8426902SWilliam A. Kennington III     {
171a8426902SWilliam A. Kennington III         auto [hdr, data] = netlink::extractRtAttr(msg);
172a8426902SWilliam A. Kennington III         if (hdr.rta_type == NDA_LLADDR)
173a8426902SWilliam A. Kennington III         {
174b7d6a1a7SWilliam A. Kennington III             ret.mac = stdplus::raw::copyFrom<stdplus::EtherAddr>(data);
175a8426902SWilliam A. Kennington III         }
176a8426902SWilliam A. Kennington III         else if (hdr.rta_type == NDA_DST)
177a8426902SWilliam A. Kennington III         {
178a8426902SWilliam A. Kennington III             ret.addr = addrFromBuf(ndm.ndm_family, data);
179a8426902SWilliam A. Kennington III         }
180a8426902SWilliam A. Kennington III     }
181a8426902SWilliam A. Kennington III     return ret;
182a8426902SWilliam A. Kennington III }
183a8426902SWilliam A. Kennington III 
184a7344c3aSWilliam A. Kennington III } // namespace phosphor::network::netlink
185