From: Tomek Mrugalski Date: Tue, 21 Feb 2012 19:13:59 +0000 (+0100) Subject: [1528] Linux-specific interface detection improved. X-Git-Tag: trac2351_base~240^2~17 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d53ab0d663c6ead51bdde2d2b16365ff6adab424;p=thirdparty%2Fkea.git [1528] Linux-specific interface detection improved. - converted C-style table of rtattr message to boost - added doxygen comments - renamed several variables to something more meaningful --- diff --git a/src/lib/dhcp/iface_mgr_linux.cc b/src/lib/dhcp/iface_mgr_linux.cc index f6c7b2fb5a..38b21347fe 100644 --- a/src/lib/dhcp/iface_mgr_linux.cc +++ b/src/lib/dhcp/iface_mgr_linux.cc @@ -12,7 +12,6 @@ // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. - #include #if defined(OS_LINUX) @@ -22,6 +21,7 @@ #include #include +#include using namespace std; using namespace isc; @@ -29,7 +29,7 @@ using namespace isc::asiolink; using namespace isc::dhcp; namespace { -/// @brief holds pointers to netlink messages +/// @brief Holds pointers to netlink messages. /// /// netlink (a Linux interface for getting information about network /// interfaces) uses memory aliasing. There are many nlmsg structures @@ -38,9 +38,20 @@ namespace { /// pointers to nlmsghdr (the common structure). typedef vector NetlinkMessages; -/// This is a structure that defines context for netlink connection. +/// @brief Holds information about interface or address attributes. +/// +/// Note that to get addres info, a shorter (IFA_MAX rather than IFLA_MAX) +/// table could be used, but we will use the bigger one anyway to +/// make any code reuse +typedef boost::array RTattribs; + +/// @brief This structure defines context for netlink connection. struct rtnl_handle { + rtnl_handle() :fd(0), seq(0), dump(0) { + memset(&local, 0, sizeof(struct sockaddr_nl)); + memset(&peer, 0, sizeof(struct sockaddr_nl)); + } int fd; // netlink file descriptor struct sockaddr_nl local; struct sockaddr_nl peer; @@ -142,12 +153,20 @@ void rtnl_store_reply(NetlinkMessages& storage, const struct nlmsghdr *msg) storage.push_back(copy); } -void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +/// @brief Parses rtattr message. +/// +/// Netlink can return a concatenated list of rtattr structures. This function iterates +/// over that list and stores pointers to those messages in flat array (table). +/// +/// @param table rtattr messages will be stored here +/// @param rta pointer to first rtattr object +/// @param len length (in bytes) of concatenated rtattr list. +void parse_rtattr(RTattribs& table, struct rtattr * rta, int len) { - memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + std::fill(table.begin(), table.end(), static_cast(NULL)); while (RTA_OK(rta, len)) { - if (rta->rta_type <= max) - tb[rta->rta_type] = rta; + if (rta->rta_type <= table.size()-1) + table[rta->rta_type] = rta; rta = RTA_NEXT(rta,len); } if (len) { @@ -155,9 +174,13 @@ void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) } } +/// @brief Parses addr_info and appends appropriate addresses to Iface object. +/// +/// @param iface interface representation (addresses will be added here) +/// @param addr_info collection of parsed netlink messages void ipaddrs_get(IfaceMgr::Iface& iface, NetlinkMessages& addr_info) { uint8_t addr[16]; - struct rtattr * rta_tb[IFA_MAX+1]; + RTattribs rta_tb; for (NetlinkMessages::const_iterator msg = addr_info.begin(); msg != addr_info.end(); ++msg) { @@ -169,8 +192,8 @@ void ipaddrs_get(IfaceMgr::Iface& iface, NetlinkMessages& addr_info) { } if ( ifa->ifa_family == AF_INET6 ) { - memset(rta_tb, 0, sizeof(rta_tb)); - parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), (*msg)->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); + std::fill(rta_tb.begin(), rta_tb.end(), static_cast(NULL)); + parse_rtattr(rta_tb, IFA_RTA(ifa), (*msg)->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (!rta_tb[IFA_ADDRESS]) @@ -184,8 +207,8 @@ void ipaddrs_get(IfaceMgr::Iface& iface, NetlinkMessages& addr_info) { } if ( ifa->ifa_family == AF_INET ) { - memset(rta_tb, 0, sizeof(rta_tb)); - parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), (*msg)->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); + std::fill(rta_tb.begin(), rta_tb.end(), static_cast(NULL)); + parse_rtattr(rta_tb, IFA_RTA(ifa), (*msg)->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (!rta_tb[IFA_ADDRESS]) @@ -198,6 +221,10 @@ void ipaddrs_get(IfaceMgr::Iface& iface, NetlinkMessages& addr_info) { } } +/// @brief Processes reply received over netlink socket. +/// +/// @param rth netlink parameters +/// @param info received netlink messages will be stored here void rtnl_process_reply(const struct rtnl_handle& rth, NetlinkMessages& info) { struct sockaddr_nl nladdr; @@ -246,7 +273,7 @@ void rtnl_process_reply(const struct rtnl_handle& rth, NetlinkMessages& info) { } if (header->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(header); + struct nlmsgerr* err = (struct nlmsgerr*)NLMSG_DATA(header); if (header->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { // we are really out of luck here. We can't even say what is // wrong as error message is truncated. D'oh. @@ -276,10 +303,12 @@ void rtnl_process_reply(const struct rtnl_handle& rth, NetlinkMessages& info) { /// /// @param messages first element of the list to be released void release_list(NetlinkMessages& messages) { - // let's free our copies of stored messages + // let's free local copies of stored messages for (NetlinkMessages::iterator msg = messages.begin(); msg != messages.end(); ++msg) { - delete(*msg); + delete (*msg); } + + // ang get rid of the message pointers as well messages.clear(); } @@ -294,14 +323,13 @@ void IfaceMgr::detectIfaces() { NetlinkMessages link_info; // link info NetlinkMessages addr_info; // address info - struct rtnl_handle handle; + struct rtnl_handle handle; // socket descriptors other rtnl-related parameters // required to display information about interface - struct ifinfomsg* ifi = NULL; - struct rtattr* tb[IFLA_MAX+1]; + struct ifinfomsg* interface_info = NULL; + RTattribs attribs_table; // table with address attributes int len = 0; - memset(tb, 0, sizeof(tb)); - memset(&handle,0, sizeof(handle)); + std::fill(attribs_table.begin(), attribs_table.end(), static_cast(NULL)); // open socket rtnl_open_socket(handle); @@ -321,33 +349,34 @@ void IfaceMgr::detectIfaces() { // Now build list with interface names for (NetlinkMessages::iterator msg = link_info.begin(); msg != link_info.end(); ++msg) { - ifi = static_cast(NLMSG_DATA(*msg)); + interface_info = static_cast(NLMSG_DATA(*msg)); len = (*msg)->nlmsg_len; - len -= NLMSG_LENGTH(sizeof(*ifi)); - parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); + len -= NLMSG_LENGTH(sizeof(*interface_info)); + parse_rtattr(attribs_table, IFLA_RTA(interface_info), len); // valgrind reports *possible* memory leak in the line below, but I do believe that this // report is bogus. Nevertheless, I've split the whole interface definition into // three separate steps for easier debugging. - const char* tmp = static_cast(RTA_DATA(tb[IFLA_IFNAME])); - string iface_name(tmp); // <--- valgrind warning here - Iface iface = Iface(iface_name, ifi->ifi_index); + const char* tmp = static_cast(RTA_DATA(attribs_table[IFLA_IFNAME])); + string iface_name(tmp); // <--- (probably bogus) valgrind warning here + Iface iface = Iface(iface_name, interface_info->ifi_index); - iface.hardware_type_ = ifi->ifi_type; - iface.setFlags(ifi->ifi_flags); + iface.hardware_type_ = interface_info->ifi_type; + iface.setFlags(interface_info->ifi_flags); iface.mac_len_ = 0; memset(iface.mac_, 0, IfaceMgr::MAX_MAC_LEN); // Does inetface has LL_ADDR? - if (tb[IFLA_ADDRESS]) { - iface.mac_len_ = RTA_PAYLOAD(tb[IFLA_ADDRESS]); + if (attribs_table[IFLA_ADDRESS]) { + iface.mac_len_ = RTA_PAYLOAD(attribs_table[IFLA_ADDRESS]); if (iface.mac_len_ > IfaceMgr::MAX_MAC_LEN) { iface.mac_len_ = 0; isc_throw(Unexpected, "Interface " << iface.getFullName() - << " was detected to have link address of length " << RTA_PAYLOAD(tb[IFLA_ADDRESS]) + << " was detected to have link address of length " + << RTA_PAYLOAD(attribs_table[IFLA_ADDRESS]) << ", but maximum supported length is " << IfaceMgr::MAX_MAC_LEN); } - memcpy(iface.mac_, RTA_DATA(tb[IFLA_ADDRESS]), iface.mac_len_); + memcpy(iface.mac_, RTA_DATA(attribs_table[IFLA_ADDRESS]), iface.mac_len_); } else { // Tunnels can have no LL_ADDR. RTA_PAYLOAD doesn't check it and try to