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 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 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 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(ether_addr)) 71 { 72 ret.mac.emplace(stdplus::raw::copyFrom<ether_addr>(data)); 73 } 74 break; 75 case IFLA_MTU: 76 ret.mtu.emplace(stdplus::raw::copyFrom<unsigned>(data)); 77 break; 78 case IFLA_LINK: 79 ret.parent_idx.emplace(stdplus::raw::copyFrom<unsigned>(data)); 80 break; 81 case IFLA_LINKINFO: 82 parseLinkInfo(ret, data); 83 break; 84 } 85 } 86 return ret; 87 } 88 89 template <typename Addr> 90 static std::optional<std::tuple<unsigned, InAddrAny>> 91 parse(std::string_view msg) 92 { 93 std::optional<unsigned> ifIdx; 94 std::optional<InAddrAny> gw; 95 while (!msg.empty()) 96 { 97 auto [hdr, data] = extractRtAttr(msg); 98 switch (hdr.rta_type) 99 { 100 case RTA_OIF: 101 ifIdx.emplace(stdplus::raw::copyFromStrict<int>(data)); 102 break; 103 case RTA_GATEWAY: 104 gw.emplace(stdplus::raw::copyFromStrict<Addr>(data)); 105 break; 106 } 107 } 108 if (ifIdx && gw) 109 { 110 return std::make_tuple(*ifIdx, *gw); 111 } 112 return std::nullopt; 113 } 114 115 std::optional<std::tuple<unsigned, InAddrAny>> 116 gatewayFromRtm(std::string_view msg) 117 { 118 const auto& rtm = extractRtData<rtmsg>(msg); 119 if (rtm.rtm_table != RT_TABLE_MAIN || rtm.rtm_dst_len != 0) 120 { 121 return std::nullopt; 122 } 123 switch (rtm.rtm_family) 124 { 125 case AF_INET: 126 return parse<in_addr>(msg); 127 case AF_INET6: 128 return parse<in6_addr>(msg); 129 } 130 return std::nullopt; 131 } 132 133 AddressInfo addrFromRtm(std::string_view msg) 134 { 135 const auto& ifa = extractRtData<ifaddrmsg>(msg); 136 137 AddressInfo ret; 138 ret.ifidx = ifa.ifa_index; 139 ret.flags = ifa.ifa_flags; 140 ret.scope = ifa.ifa_scope; 141 std::optional<InAddrAny> addr; 142 while (!msg.empty()) 143 { 144 auto [hdr, data] = extractRtAttr(msg); 145 if (hdr.rta_type == IFA_ADDRESS) 146 { 147 addr.emplace(addrFromBuf(ifa.ifa_family, data)); 148 } 149 else if (hdr.rta_type == IFA_FLAGS) 150 { 151 ret.flags = stdplus::raw::copyFromStrict<uint32_t>(data); 152 } 153 } 154 if (!addr) 155 { 156 throw std::runtime_error("Missing address"); 157 } 158 ret.ifaddr = {*addr, ifa.ifa_prefixlen}; 159 return ret; 160 } 161 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<ether_addr>(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