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.flags = ifinfo.ifi_flags; 59 ret.idx = ifinfo.ifi_index; 60 while (!msg.empty()) 61 { 62 auto [hdr, data] = netlink::extractRtAttr(msg); 63 switch (hdr.rta_type) 64 { 65 case IFLA_IFNAME: 66 ret.name.emplace(data.begin(), data.end() - 1); 67 break; 68 case IFLA_ADDRESS: 69 if (data.size() == sizeof(ether_addr)) 70 { 71 ret.mac.emplace(stdplus::raw::copyFrom<ether_addr>(data)); 72 } 73 break; 74 case IFLA_MTU: 75 ret.mtu.emplace(stdplus::raw::copyFrom<unsigned>(data)); 76 break; 77 case IFLA_LINK: 78 ret.parent_idx.emplace(stdplus::raw::copyFrom<unsigned>(data)); 79 break; 80 case IFLA_LINKINFO: 81 parseLinkInfo(ret, data); 82 break; 83 } 84 } 85 return ret; 86 } 87 88 template <typename Addr> 89 static std::optional<std::tuple<unsigned, InAddrAny>> 90 parse(std::string_view msg) 91 { 92 std::optional<unsigned> ifIdx; 93 std::optional<InAddrAny> gw; 94 while (!msg.empty()) 95 { 96 auto [hdr, data] = extractRtAttr(msg); 97 switch (hdr.rta_type) 98 { 99 case RTA_OIF: 100 ifIdx.emplace(stdplus::raw::copyFromStrict<int>(data)); 101 break; 102 case RTA_GATEWAY: 103 gw.emplace(stdplus::raw::copyFromStrict<Addr>(data)); 104 break; 105 } 106 } 107 if (ifIdx && gw) 108 { 109 return std::make_tuple(*ifIdx, *gw); 110 } 111 return std::nullopt; 112 } 113 114 std::optional<std::tuple<unsigned, InAddrAny>> 115 gatewayFromRtm(std::string_view msg) 116 { 117 const auto& rtm = extractRtData<rtmsg>(msg); 118 if (rtm.rtm_table != RT_TABLE_MAIN || rtm.rtm_dst_len != 0) 119 { 120 return std::nullopt; 121 } 122 switch (rtm.rtm_family) 123 { 124 case AF_INET: 125 return parse<in_addr>(msg); 126 case AF_INET6: 127 return parse<in6_addr>(msg); 128 } 129 return std::nullopt; 130 } 131 132 AddressInfo addrFromRtm(std::string_view msg) 133 { 134 const auto& ifa = extractRtData<ifaddrmsg>(msg); 135 136 AddressInfo ret; 137 ret.ifidx = ifa.ifa_index; 138 ret.flags = ifa.ifa_flags; 139 ret.scope = ifa.ifa_scope; 140 std::optional<InAddrAny> addr; 141 while (!msg.empty()) 142 { 143 auto [hdr, data] = extractRtAttr(msg); 144 if (hdr.rta_type == IFA_ADDRESS) 145 { 146 addr.emplace(addrFromBuf(ifa.ifa_family, data)); 147 } 148 else if (hdr.rta_type == IFA_FLAGS) 149 { 150 ret.flags = stdplus::raw::copyFromStrict<uint32_t>(data); 151 } 152 } 153 if (!addr) 154 { 155 throw std::runtime_error("Missing address"); 156 } 157 ret.ifaddr = {*addr, ifa.ifa_prefixlen}; 158 return ret; 159 } 160 161 NeighborInfo neighFromRtm(std::string_view msg) 162 { 163 const auto& ndm = netlink::extractRtData<ndmsg>(msg); 164 165 NeighborInfo ret; 166 ret.ifidx = ndm.ndm_ifindex; 167 ret.state = ndm.ndm_state; 168 while (!msg.empty()) 169 { 170 auto [hdr, data] = netlink::extractRtAttr(msg); 171 if (hdr.rta_type == NDA_LLADDR) 172 { 173 ret.mac = stdplus::raw::copyFrom<ether_addr>(data); 174 } 175 else if (hdr.rta_type == NDA_DST) 176 { 177 ret.addr = addrFromBuf(ndm.ndm_family, data); 178 } 179 } 180 return ret; 181 } 182 183 } // namespace phosphor::network::netlink 184