xref: /openbmc/phosphor-networkd/src/rtnetlink.cpp (revision 9c441fd469094518d5c2ad03b5dc117a2aa9bec8)
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 
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 
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 
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;
58*9c441fd4SWilliam A. Kennington III     ret.type = ifinfo.ifi_type;
591aeacc90SWilliam A. Kennington III     ret.idx = ifinfo.ifi_index;
60*9c441fd4SWilliam 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:
701aeacc90SWilliam A. Kennington III                 if (data.size() == sizeof(ether_addr))
711aeacc90SWilliam A. Kennington III                 {
721aeacc90SWilliam A. Kennington III                     ret.mac.emplace(stdplus::raw::copyFrom<ether_addr>(data));
731aeacc90SWilliam A. Kennington III                 }
741aeacc90SWilliam A. Kennington III                 break;
751aeacc90SWilliam A. Kennington III             case IFLA_MTU:
761aeacc90SWilliam A. Kennington III                 ret.mtu.emplace(stdplus::raw::copyFrom<unsigned>(data));
771aeacc90SWilliam A. Kennington III                 break;
781aeacc90SWilliam A. Kennington III             case IFLA_LINK:
791aeacc90SWilliam A. Kennington III                 ret.parent_idx.emplace(stdplus::raw::copyFrom<unsigned>(data));
801aeacc90SWilliam A. Kennington III                 break;
811aeacc90SWilliam A. Kennington III             case IFLA_LINKINFO:
821aeacc90SWilliam A. Kennington III                 parseLinkInfo(ret, data);
831aeacc90SWilliam A. Kennington III                 break;
841aeacc90SWilliam A. Kennington III         }
851aeacc90SWilliam A. Kennington III     }
861aeacc90SWilliam A. Kennington III     return ret;
871aeacc90SWilliam A. Kennington III }
881aeacc90SWilliam A. Kennington III 
89a7344c3aSWilliam A. Kennington III template <typename Addr>
90a7344c3aSWilliam A. Kennington III static std::optional<std::tuple<unsigned, InAddrAny>>
91a7344c3aSWilliam A. Kennington III     parse(std::string_view msg)
92a7344c3aSWilliam A. Kennington III {
93a7344c3aSWilliam A. Kennington III     std::optional<unsigned> ifIdx;
94a7344c3aSWilliam A. Kennington III     std::optional<InAddrAny> gw;
95a7344c3aSWilliam A. Kennington III     while (!msg.empty())
96a7344c3aSWilliam A. Kennington III     {
97a7344c3aSWilliam A. Kennington III         auto [hdr, data] = extractRtAttr(msg);
98a7344c3aSWilliam A. Kennington III         switch (hdr.rta_type)
99a7344c3aSWilliam A. Kennington III         {
100a7344c3aSWilliam A. Kennington III             case RTA_OIF:
1016a92363eSWilliam A. Kennington III                 ifIdx.emplace(stdplus::raw::copyFromStrict<int>(data));
102a7344c3aSWilliam A. Kennington III                 break;
103a7344c3aSWilliam A. Kennington III             case RTA_GATEWAY:
1046a92363eSWilliam A. Kennington III                 gw.emplace(stdplus::raw::copyFromStrict<Addr>(data));
105a7344c3aSWilliam A. Kennington III                 break;
106a7344c3aSWilliam A. Kennington III         }
107a7344c3aSWilliam A. Kennington III     }
108a7344c3aSWilliam A. Kennington III     if (ifIdx && gw)
109a7344c3aSWilliam A. Kennington III     {
110a7344c3aSWilliam A. Kennington III         return std::make_tuple(*ifIdx, *gw);
111a7344c3aSWilliam A. Kennington III     }
112a7344c3aSWilliam A. Kennington III     return std::nullopt;
113a7344c3aSWilliam A. Kennington III }
114a7344c3aSWilliam A. Kennington III 
115a7344c3aSWilliam A. Kennington III std::optional<std::tuple<unsigned, InAddrAny>>
116a7344c3aSWilliam A. Kennington III     gatewayFromRtm(std::string_view msg)
117a7344c3aSWilliam A. Kennington III {
118a7344c3aSWilliam A. Kennington III     const auto& rtm = extractRtData<rtmsg>(msg);
119a7344c3aSWilliam A. Kennington III     if (rtm.rtm_table != RT_TABLE_MAIN || rtm.rtm_dst_len != 0)
120a7344c3aSWilliam A. Kennington III     {
121a7344c3aSWilliam A. Kennington III         return std::nullopt;
122a7344c3aSWilliam A. Kennington III     }
123a7344c3aSWilliam A. Kennington III     switch (rtm.rtm_family)
124a7344c3aSWilliam A. Kennington III     {
125a7344c3aSWilliam A. Kennington III         case AF_INET:
126a7344c3aSWilliam A. Kennington III             return parse<in_addr>(msg);
127a7344c3aSWilliam A. Kennington III         case AF_INET6:
128a7344c3aSWilliam A. Kennington III             return parse<in6_addr>(msg);
129a7344c3aSWilliam A. Kennington III     }
130a7344c3aSWilliam A. Kennington III     return std::nullopt;
131a7344c3aSWilliam A. Kennington III }
132a7344c3aSWilliam A. Kennington III 
1336a92363eSWilliam A. Kennington III AddressInfo addrFromRtm(std::string_view msg)
1346a92363eSWilliam A. Kennington III {
1356a92363eSWilliam A. Kennington III     const auto& ifa = extractRtData<ifaddrmsg>(msg);
1366a92363eSWilliam A. Kennington III 
1376a92363eSWilliam A. Kennington III     AddressInfo ret;
1386a92363eSWilliam A. Kennington III     ret.ifidx = ifa.ifa_index;
1396a92363eSWilliam A. Kennington III     ret.flags = ifa.ifa_flags;
1406a92363eSWilliam A. Kennington III     ret.scope = ifa.ifa_scope;
1416a92363eSWilliam A. Kennington III     std::optional<InAddrAny> addr;
1426a92363eSWilliam A. Kennington III     while (!msg.empty())
1436a92363eSWilliam A. Kennington III     {
1446a92363eSWilliam A. Kennington III         auto [hdr, data] = extractRtAttr(msg);
1456a92363eSWilliam A. Kennington III         if (hdr.rta_type == IFA_ADDRESS)
1466a92363eSWilliam A. Kennington III         {
1476a92363eSWilliam A. Kennington III             addr.emplace(addrFromBuf(ifa.ifa_family, data));
1486a92363eSWilliam A. Kennington III         }
1496a92363eSWilliam A. Kennington III         else if (hdr.rta_type == IFA_FLAGS)
1506a92363eSWilliam A. Kennington III         {
1516a92363eSWilliam A. Kennington III             ret.flags = stdplus::raw::copyFromStrict<uint32_t>(data);
1526a92363eSWilliam A. Kennington III         }
1536a92363eSWilliam A. Kennington III     }
1546a92363eSWilliam A. Kennington III     if (!addr)
1556a92363eSWilliam A. Kennington III     {
1566a92363eSWilliam A. Kennington III         throw std::runtime_error("Missing address");
1576a92363eSWilliam A. Kennington III     }
1586a92363eSWilliam A. Kennington III     ret.ifaddr = {*addr, ifa.ifa_prefixlen};
1596a92363eSWilliam A. Kennington III     return ret;
1606a92363eSWilliam A. Kennington III }
1616a92363eSWilliam A. Kennington III 
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         {
174a8426902SWilliam A. Kennington III             ret.mac = stdplus::raw::copyFrom<ether_addr>(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