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 template <typename Addr>
12 static std::optional<std::tuple<unsigned, InAddrAny>>
13     parse(std::string_view msg)
14 {
15     std::optional<unsigned> ifIdx;
16     std::optional<InAddrAny> gw;
17     while (!msg.empty())
18     {
19         auto [hdr, data] = extractRtAttr(msg);
20         switch (hdr.rta_type)
21         {
22             case RTA_OIF:
23                 ifIdx.emplace(stdplus::raw::copyFromStrict<int>(data));
24                 break;
25             case RTA_GATEWAY:
26                 gw.emplace(stdplus::raw::copyFromStrict<Addr>(data));
27                 break;
28         }
29     }
30     if (ifIdx && gw)
31     {
32         return std::make_tuple(*ifIdx, *gw);
33     }
34     return std::nullopt;
35 }
36 
37 std::optional<std::tuple<unsigned, InAddrAny>>
38     gatewayFromRtm(std::string_view msg)
39 {
40     const auto& rtm = extractRtData<rtmsg>(msg);
41     if (rtm.rtm_table != RT_TABLE_MAIN || rtm.rtm_dst_len != 0)
42     {
43         return std::nullopt;
44     }
45     switch (rtm.rtm_family)
46     {
47         case AF_INET:
48             return parse<in_addr>(msg);
49         case AF_INET6:
50             return parse<in6_addr>(msg);
51     }
52     return std::nullopt;
53 }
54 
55 AddressInfo addrFromRtm(std::string_view msg)
56 {
57     const auto& ifa = extractRtData<ifaddrmsg>(msg);
58 
59     AddressInfo ret;
60     ret.ifidx = ifa.ifa_index;
61     ret.flags = ifa.ifa_flags;
62     ret.scope = ifa.ifa_scope;
63     std::optional<InAddrAny> addr;
64     while (!msg.empty())
65     {
66         auto [hdr, data] = extractRtAttr(msg);
67         if (hdr.rta_type == IFA_ADDRESS)
68         {
69             addr.emplace(addrFromBuf(ifa.ifa_family, data));
70         }
71         else if (hdr.rta_type == IFA_FLAGS)
72         {
73             ret.flags = stdplus::raw::copyFromStrict<uint32_t>(data);
74         }
75     }
76     if (!addr)
77     {
78         throw std::runtime_error("Missing address");
79     }
80     ret.ifaddr = {*addr, ifa.ifa_prefixlen};
81     return ret;
82 }
83 
84 NeighborInfo neighFromRtm(std::string_view msg)
85 {
86     const auto& ndm = netlink::extractRtData<ndmsg>(msg);
87 
88     NeighborInfo ret;
89     ret.ifidx = ndm.ndm_ifindex;
90     ret.state = ndm.ndm_state;
91     bool set_addr = false;
92     while (!msg.empty())
93     {
94         auto [hdr, data] = netlink::extractRtAttr(msg);
95         if (hdr.rta_type == NDA_LLADDR)
96         {
97             ret.mac = stdplus::raw::copyFrom<ether_addr>(data);
98         }
99         else if (hdr.rta_type == NDA_DST)
100         {
101             ret.addr = addrFromBuf(ndm.ndm_family, data);
102             set_addr = true;
103         }
104     }
105     if (!set_addr)
106     {
107         throw std::runtime_error("Missing address");
108     }
109     return ret;
110 }
111 
112 } // namespace phosphor::network::netlink
113