Browse Source

[1237] OS-detection cleanup, Linux-specific IfaceMgr cleanup.

Tomek Mrugalski 13 years ago
parent
commit
5ec569cd8c
4 changed files with 231 additions and 230 deletions
  1. 6 3
      configure.ac
  2. 0 6
      src/lib/dhcp/Makefile.am
  3. 6 11
      src/lib/dhcp/iface_mgr_bsd.cc
  4. 219 210
      src/lib/dhcp/iface_mgr_linux.cc

+ 6 - 3
configure.ac

@@ -373,7 +373,7 @@ AC_MSG_CHECKING(OS family)
 system=`uname -s`
 case $system in
     Linux)
-      OS_TYPE="LINUX"
+      OS_TYPE="Linux"
       CPPFLAGS="$CPPFLAGS -DOS_LINUX"
       ;;
     Darwin | FreeBSD | NetBSD | OpenBSD)
@@ -390,10 +390,13 @@ case $system in
       ;;
 esac
 AC_MSG_RESULT($OS_TYPE)
-AM_CONDITIONAL(OS_LINUX, test $OS_TYPE = LINUX)
+
+AM_CONDITIONAL(OS_LINUX, test $OS_TYPE = Linux)
+AM_COND_IF([OS_LINUX], [AC_DEFINE([OS_LINUX], [1], [Running on Linux?])])
 AM_CONDITIONAL(OS_BSD, test $OS_TYPE = BSD)
+AM_COND_IF([OS_BSD], [AC_DEFINE([OS_BSD], [1], [Running on BSD?])])
 AM_CONDITIONAL(OS_SOLARIS, test $OS_TYPE = Solaris)
-
+AM_COND_IF([OS_SOLARIS], [AC_DEFINE([OS_SOLARIS], [1], [Running on Solaris?])])
 
 AC_MSG_CHECKING(for sa_len in struct sockaddr)
 AC_TRY_COMPILE([

+ 0 - 6
src/lib/dhcp/Makefile.am

@@ -18,14 +18,8 @@ libdhcp_la_SOURCES += option6_addrlst.cc option6_addrlst.h
 libdhcp_la_SOURCES += dhcp6.h dhcp4.h
 libdhcp_la_SOURCES += pkt6.cc pkt6.h
 libdhcp_la_SOURCES += pkt4.cc pkt4.h
-
-if OS_LINUX
 libdhcp_la_SOURCES += iface_mgr_linux.cc
-endif
-
-if OS_BSD
 libdhcp_la_SOURCES += iface_mgr_bsd.cc
-endif
 
 
 EXTRA_DIST  = README

+ 6 - 11
src/lib/dhcp/iface_mgr_bsd.cc

@@ -12,6 +12,10 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <config.h>
+
+#if defined(OS_BSD)
+
 #include <dhcp/iface_mgr.h>
 #include <exceptions/exceptions.h>
 
@@ -20,17 +24,6 @@ using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
 
-#if !defined(OS_BSD)
-/// There are several detectIfaces() implementations for specific
-/// Operating Systems. This one is specific to BSD. It works on
-/// BSD only, so it does not make sense to try to compile it somewhere
-/// else. In particular, Makefile.am includes only one iface_mgr_{OS_TYPE}.cc
-/// file.
-
-#error "Attempt to compile iface_mgr_bsd.cc on non-BSD system!"
-
-#endif
-
 namespace isc {
 
 void
@@ -41,3 +34,5 @@ IfaceMgr::detectIfaces() {
 }
 
 }
+
+#endif

+ 219 - 210
src/lib/dhcp/iface_mgr_linux.cc

@@ -12,6 +12,11 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+
+#include <config.h>
+
+#if defined(OS_LINUX)
+
 #include <dhcp/iface_mgr.h>
 #include <exceptions/exceptions.h>
 
@@ -24,29 +29,20 @@ using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
 
-#if !defined(OS_LINUX)
-/// There are several detectIfaces() implementations for specific
-/// Operating Systems. This one is specific to Linux. It works on
-/// Linux only, so it does not make sense to try to compile it somewhere
-/// else. In particular, Makefile.am includes only one iface_mgr_{OS_TYPE}.cc
-/// file.
-
-#error "Attempt to compile iface_mgr_linux.cc on non-Linux system!"
-#endif
-
+/// This is a structure that defines context for netlink connection.
 struct rtnl_handle
 {
-	int			fd;
-	struct sockaddr_nl	local;
-	struct sockaddr_nl	peer;
-	__u32			seq;
-	__u32			dump;
+    int                fd;
+    struct sockaddr_nl local;
+    struct sockaddr_nl peer;
+    __u32              seq;
+    __u32              dump;
 };
 
 struct nlmsg_list
 {
-	struct nlmsg_list *next;
-	struct nlmsghdr	  h;
+    struct nlmsg_list *next;
+    struct nlmsghdr h;
 };
 
 const int sndbuf = 32768;
@@ -55,53 +51,61 @@ const int rcvbuf = 32768;
 namespace isc {
 
 
+/// @brief Opens netlink socket and initializes handle structure.
+///
+/// @exception Unexpected Thrown if socket configuration fails.
+///
+/// @param handle Context will be stored in this structure.
 void rtnl_open_socket(struct rtnl_handle& handle) {
     // equivalent of rtnl_open
     handle.fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
     if (handle.fd < 0) {
-	isc_throw(Unexpected, "Failed to create NETLINK socket.");
+        isc_throw(Unexpected, "Failed to create NETLINK socket.");
     }
-    
+
     if (setsockopt(handle.fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) {
-	isc_throw(Unexpected, "Failed to set send buffer in NETLINK socket.");
+        isc_throw(Unexpected, "Failed to set send buffer in NETLINK socket.");
     }
-    
+
     if (setsockopt(handle.fd, SOL_SOCKET, SO_RCVBUF, &sndbuf, sizeof(rcvbuf)) < 0) {
-	isc_throw(Unexpected, "Failed to set receive buffer in NETLINK socket.");
+        isc_throw(Unexpected, "Failed to set receive buffer in NETLINK socket.");
     }
-    
+
     memset(&handle.local, 0, sizeof(handle.local));
     handle.local.nl_family = AF_NETLINK;
     handle.local.nl_groups = 0;
 
     if (bind(handle.fd, (struct sockaddr*)&handle.local, sizeof(handle.local)) < 0) {
-	isc_throw(Unexpected, "Failed to bind netlink socket.");
+        isc_throw(Unexpected, "Failed to bind netlink socket.");
     }
 
     socklen_t addr_len = sizeof(handle.local);
     if (getsockname(handle.fd, (struct sockaddr*)&handle.local, &addr_len) < 0) {
-	isc_throw(Unexpected, "Getsockname for netlink socket failed.");
+        isc_throw(Unexpected, "Getsockname for netlink socket failed.");
     }
 
     // just 2 sanity checks and we are done
     if ( (addr_len != sizeof(handle.local)) ||
-	 (handle.local.nl_family != AF_NETLINK) ) {
-	isc_throw(Unexpected, "getsockname() returned unexpected data for netlink socket.");
+         (handle.local.nl_family != AF_NETLINK) ) {
+        isc_throw(Unexpected, "getsockname() returned unexpected data for netlink socket.");
     }
 }
 
-// sends request over NETLINK socket
-void rtnl_send_request(struct rtnl_handle& handle,
-		       int family, int type) {
+/// @brief Sends request over NETLINK socket.
+///
+/// @param handle context structure
+/// @param family requested information family
+/// @param type request type (RTM_GETLINK or RTM_GETADDR)
+void rtnl_send_request(struct rtnl_handle& handle, int family, int type) {
     struct {
-	struct nlmsghdr nlh;
-	struct rtgenmsg g;
+        struct nlmsghdr nlh;
+        struct rtgenmsg g;
     } req;
     struct sockaddr_nl nladdr;
-    
+
     memset(&nladdr, 0, sizeof(nladdr));
     nladdr.nl_family = AF_NETLINK;
-    
+
     memset(&req, 0, sizeof(req));
     req.nlh.nlmsg_len = sizeof(req);
     req.nlh.nlmsg_type = type;
@@ -109,98 +113,95 @@ void rtnl_send_request(struct rtnl_handle& handle,
     req.nlh.nlmsg_pid = 0;
     req.nlh.nlmsg_seq = handle.dump = ++handle.seq;
     req.g.rtgen_family = family;
-    
+
     int status =  sendto(handle.fd, (void*)&req, sizeof(req), 0,
-			 (struct sockaddr*)&nladdr, sizeof(nladdr));
+                         (struct sockaddr*)&nladdr, sizeof(nladdr));
 
     if (status<0) {
-	isc_throw(Unexpected, "Failed to send " << sizeof(nladdr) << " bytes over netlink socket.");
+        isc_throw(Unexpected, "Failed to send " << sizeof(nladdr) << " bytes over netlink socket.");
     }
 }
 
-void rtnl_store_reply(/*const struct sockaddr_nl *who,*/ struct nlmsghdr *n, struct nlmsg_list** linfo)
+/// @brief Appends nlmsg to a list
+///
+/// @param n a message to be added
+/// @param link_info a list
+void rtnl_store_reply(struct nlmsghdr *n, struct nlmsg_list** link_info)
 {
     struct nlmsg_list *h;
     struct nlmsg_list **lp;
-    
+
     h = (nlmsg_list*)malloc(n->nlmsg_len+sizeof(void*));
     if (h == NULL) {
-	isc_throw(Unexpected, "Failed to allocate " << n->nlmsg_len+sizeof(void*)
-		  << " bytes.");
+        isc_throw(Unexpected, "Failed to allocate " << n->nlmsg_len+sizeof(void*)
+                  << " bytes.");
     }
-    
+
     memcpy(&h->h, n, n->nlmsg_len);
     h->next = NULL;
-    
-    for (lp = linfo; *lp; lp = &(*lp)->next) /* NOTHING */;
+
+    for (lp = link_info; *lp; lp = &(*lp)->next) /* NOTHING */;
     *lp = h;
-    
-    // ll_remember_index(who, n, NULL);
-    // return 0;
 }
 
 void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
 {
     memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
     while (RTA_OK(rta, len)) {
-	if (rta->rta_type <= max)
-	    tb[rta->rta_type] = rta;
-	rta = RTA_NEXT(rta,len);
+        if (rta->rta_type <= max)
+            tb[rta->rta_type] = rta;
+        rta = RTA_NEXT(rta,len);
     }
     if (len) {
-	isc_throw(Unexpected, "Failed to parse RTATTR in netlink message.");
+        isc_throw(Unexpected, "Failed to parse RTATTR in netlink message.");
     }
 }
 
-
- void ipaddrs_get(IfaceMgr::Iface& iface, struct nlmsg_list *ainfo) {
+void ipaddrs_get(IfaceMgr::Iface& iface, struct nlmsg_list *addr_info) {
     uint8_t addr[16];
     struct rtattr * rta_tb[IFA_MAX+1];
 
-    for ( ;ainfo ;  ainfo = ainfo->next) {
-	struct nlmsghdr *n = &ainfo->h;
-	struct ifaddrmsg *ifa = (ifaddrmsg*)NLMSG_DATA(n);
-
-	// these are not the addresses you are looking for
-	if ( ifa->ifa_index != iface.ifindex_) {
-	    continue;
-	}
-
-	if ( ifa->ifa_family == AF_INET6 ) {
-	    memset(rta_tb, 0, sizeof(rta_tb));
-	    parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
-	    if (!rta_tb[IFA_LOCAL])   
-		rta_tb[IFA_LOCAL]   = rta_tb[IFA_ADDRESS];
-	    if (!rta_tb[IFA_ADDRESS]) 
-		rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
-	    
-	    memcpy(addr,(char*)RTA_DATA(rta_tb[IFLA_ADDRESS]),16);
-	    IOAddress a = IOAddress::from_bytes(AF_INET6, addr);
-	    iface.addrs_.push_back(a);
-
-	    /// TODO: Read lifetimes of configured addresses
-	}
-
-	if ( ifa->ifa_family == AF_INET ) {
-	    memset(rta_tb, 0, sizeof(rta_tb));
-	    parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
-	    if (!rta_tb[IFA_LOCAL])   
-		rta_tb[IFA_LOCAL]   = rta_tb[IFA_ADDRESS];
-	    if (!rta_tb[IFA_ADDRESS]) 
-		rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
-	    
-	    memcpy(addr,(char*)RTA_DATA(rta_tb[IFLA_ADDRESS]),4);
-	    IOAddress a = IOAddress::from_bytes(AF_INET, addr);
-	    iface.addrs_.push_back(a);
-	}
-
-
+    for ( ;addr_info ;  addr_info = addr_info->next) {
+        struct nlmsghdr *n = &addr_info->h;
+        struct ifaddrmsg *ifa = (ifaddrmsg*)NLMSG_DATA(n);
+
+        // these are not the addresses you are looking for
+        if ( ifa->ifa_index != iface.ifindex_) {
+            continue;
+        }
+
+        if ( ifa->ifa_family == AF_INET6 ) {
+            memset(rta_tb, 0, sizeof(rta_tb));
+            parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
+            if (!rta_tb[IFA_LOCAL])
+                rta_tb[IFA_LOCAL]   = rta_tb[IFA_ADDRESS];
+            if (!rta_tb[IFA_ADDRESS])
+                rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
+
+            memcpy(addr,(char*)RTA_DATA(rta_tb[IFLA_ADDRESS]),16);
+            IOAddress a = IOAddress::from_bytes(AF_INET6, addr);
+            iface.addrs_.push_back(a);
+
+            /// TODO: Read lifetimes of configured addresses
+        }
+
+        if ( ifa->ifa_family == AF_INET ) {
+            memset(rta_tb, 0, sizeof(rta_tb));
+            parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
+            if (!rta_tb[IFA_LOCAL])
+                rta_tb[IFA_LOCAL]   = rta_tb[IFA_ADDRESS];
+            if (!rta_tb[IFA_ADDRESS])
+                rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
+
+            memcpy(addr,(char*)RTA_DATA(rta_tb[IFLA_ADDRESS]),4);
+            IOAddress a = IOAddress::from_bytes(AF_INET, addr);
+            iface.addrs_.push_back(a);
+        }
     }
 }
 
 
-void rtnl_process_reply(struct rtnl_handle &rth,
-		       struct nlmsg_list *&info) {
+void rtnl_process_reply(struct rtnl_handle &rth, struct nlmsg_list *&info) {
 
     struct sockaddr_nl nladdr;
     struct iovec iov;
@@ -212,91 +213,91 @@ void rtnl_process_reply(struct rtnl_handle &rth,
     msg.msg_iovlen = 1;
 
     char buf[rcvbuf];
-    
+
     iov.iov_base = buf;
     while (1) {
-	int status;
-	struct nlmsghdr *h;
-	
-	iov.iov_len = sizeof(buf);
-	status = recvmsg(rth.fd, &msg, 0);
-	
-	if (status < 0) {
-	    if (errno == EINTR)
-		continue;
-	    isc_throw(Unexpected, "Overrun while processing reply from netlink socket.");
-	}
-	
-	if (status == 0) {
-	    isc_throw(Unexpected, "EOF while reading netlink socket.");
-	}
-	
-	h = (struct nlmsghdr*)buf;
-	while (NLMSG_OK(h, status)) {
-
-	    // why we received this anyway?
-	    if (nladdr.nl_pid != 0 ||
-		h->nlmsg_pid != rth.local.nl_pid ||
-		h->nlmsg_seq != rth.dump) {
-		h = NLMSG_NEXT(h, status);
-		continue;
-	    }
-		    
-	    if (h->nlmsg_type == NLMSG_DONE) {
-		// end of message
-		return;
-	    }
-
-	    if (h->nlmsg_type == NLMSG_ERROR) {
-		struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
-		if (h->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.
-		    isc_throw(Unexpected, "Netlink reply read failed.");
-		} else {
-		    isc_throw(Unexpected, "Netlink reply read error " << -err->error);
-		}
-		// never happens we throw before we reach here
-		return;
-	    }
-
-	    // store the data 
-	    rtnl_store_reply(/*&nladdr,*/ h, &info);
-	    
-	    h = NLMSG_NEXT(h, status);
-	}
-	if (msg.msg_flags & MSG_TRUNC) {
-	    isc_throw(Unexpected, "Message received over netlink truncated.");
-	}
-	if (status) {
-	    isc_throw(Unexpected, "Trailing garbage of " << status << " bytes received over netlink.");
-	}
+        int status;
+        struct nlmsghdr *h;
+
+        iov.iov_len = sizeof(buf);
+        status = recvmsg(rth.fd, &msg, 0);
+
+        if (status < 0) {
+            if (errno == EINTR)
+                continue;
+            isc_throw(Unexpected, "Overrun while processing reply from netlink socket.");
+        }
+
+        if (status == 0) {
+            isc_throw(Unexpected, "EOF while reading netlink socket.");
+        }
+
+        h = (struct nlmsghdr*)buf;
+        while (NLMSG_OK(h, status)) {
+
+            // why we received this anyway?
+            if (nladdr.nl_pid != 0 ||
+                h->nlmsg_pid != rth.local.nl_pid ||
+                h->nlmsg_seq != rth.dump) {
+                h = NLMSG_NEXT(h, status);
+                continue;
+            }
+
+            if (h->nlmsg_type == NLMSG_DONE) {
+                // end of message
+                return;
+            }
+
+            if (h->nlmsg_type == NLMSG_ERROR) {
+                struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+                if (h->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.
+                    isc_throw(Unexpected, "Netlink reply read failed.");
+                } else {
+                    isc_throw(Unexpected, "Netlink reply read error " << -err->error);
+                }
+                // never happens we throw before we reach here
+                return;
+            }
+
+            // store the data
+            rtnl_store_reply(h, &info);
+
+            h = NLMSG_NEXT(h, status);
+        }
+        if (msg.msg_flags & MSG_TRUNC) {
+            isc_throw(Unexpected, "Message received over netlink truncated.");
+        }
+        if (status) {
+            isc_throw(Unexpected, "Trailing garbage of " << status << " bytes received over netlink.");
+        }
     }
 }
 
-void release_list(struct nlmsg_list *n) {
+/// @brief releases nlmsg list
+///
+/// @param head first element of the list to be released
+void release_list(struct nlmsg_list *head) {
     struct nlmsg_list *tmp;
-    while (n) {
-	tmp = n->next;
-	free(n);
-	n = tmp;
+    while (head) {
+        tmp = head->next;
+        free(head);
+        head = tmp;
     }
 }
 
-    
-void
-IfaceMgr::detectIfaces() {
-
+void IfaceMgr::detectIfaces() {
     cout << "Linux: detecting interfaces." << endl;
 
-    struct nlmsg_list *linfo = NULL;
-    struct nlmsg_list *ainfo = NULL;
-    struct nlmsg_list *l = NULL;
+    struct nlmsg_list* link_info = NULL; // link info list
+    struct nlmsg_list* addr_info = NULL; // address info list
+    struct nlmsg_list* l = NULL;
     struct rtnl_handle rth;
 
-    /* required to display information about interface */
-    struct ifinfomsg *ifi = NULL;
-    struct rtattr * tb[IFLA_MAX+1];
+    // required to display information about interface
+    struct ifinfomsg* ifi = NULL;
+    struct rtattr* tb[IFLA_MAX+1];
     int len = 0;
     memset(tb, 0, sizeof(tb));
     memset(&rth,0, sizeof(rth));
@@ -305,60 +306,66 @@ IfaceMgr::detectIfaces() {
     rtnl_open_socket(rth);
 
     // now we have open functional socket, let's use it!
+    // ask for list of interface...
     rtnl_send_request(rth, AF_PACKET, RTM_GETLINK);
 
-    // process reply
-    rtnl_process_reply(rth, linfo);
-    //rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL);
-    
-    /* 2nd attribute: AF_UNSPEC, AF_INET, AF_INET6 */
+    // Get reply and store it in link_info list.
+    rtnl_process_reply(rth, link_info);
+
+    // Now ask for list of addresses (AF_UNSPEC = of any family)
     rtnl_send_request(rth, AF_UNSPEC, RTM_GETADDR);
-    rtnl_process_reply(rth, ainfo);
-
-    /* build list with interface names */
-    for (l=linfo; l; l = l->next) {
-	ifi = (ifinfomsg*)NLMSG_DATA(&l->h);
-	len = (&l->h)->nlmsg_len;
-	len -= NLMSG_LENGTH(sizeof(*ifi));
-	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
-
-	Iface* iface = new Iface(string( (char*)RTA_DATA(tb[IFLA_IFNAME])), ifi->ifi_index);
-
-	iface->hardware_type_ = ifi->ifi_type;
-	iface->setFlags(ifi->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 (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])
-			  << ", but maximum supported length is " << IfaceMgr::MAX_MAC_LEN);
-	    }
-	    memcpy(iface->mac_, RTA_DATA(tb[IFLA_ADDRESS]), iface->mac_len_);
-	}
-	else {
-	    /* Tunnels can have no LL_ADDR. RTA_PAYLOAD doesn't check it and try to
-	     * dereference it in this manner
-	     * #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
-	     */
-	    iface->mac_len_ = 0;
-	}
-
-	ipaddrs_get(*iface, ainfo);
-	ifaces_.push_back(*iface);
-    }
 
+    // Get reply and store it in addr_info list.
+    rtnl_process_reply(rth, addr_info);
+
+    // Now build list with interface names
+    for (l=link_info; l; l = l->next) {
+        ifi = (ifinfomsg*)NLMSG_DATA(&l->h);
+        len = (&l->h)->nlmsg_len;
+        len -= NLMSG_LENGTH(sizeof(*ifi));
+        parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
+
+        Iface* iface = new Iface(string( (char*)RTA_DATA(tb[IFLA_IFNAME])), ifi->ifi_index);
+
+        iface->hardware_type_ = ifi->ifi_type;
+        iface->setFlags(ifi->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 (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])
+                          << ", but maximum supported length is " << IfaceMgr::MAX_MAC_LEN);
+            }
+            memcpy(iface->mac_, RTA_DATA(tb[IFLA_ADDRESS]), iface->mac_len_);
+        }
+        else {
+            // Tunnels can have no LL_ADDR. RTA_PAYLOAD doesn't check it and try to
+            // dereference it in this manner
+            // #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
+            iface->mac_len_ = 0;
+        }
+
+        ipaddrs_get(*iface, addr_info);
+        ifaces_.push_back(*iface);
+    }
 
-    release_list(linfo);
-    release_list(ainfo);
+    release_list(link_info);
+    release_list(addr_info);
 
     printIfaces();
 }
 
+/// @brief sets flag_*_ fields.
+///
+/// This implementation is OS-specific as bits have different meaning
+/// on different OSes.
+///
+/// @param flags flags bitfield read from OS
 void IfaceMgr::Iface::setFlags(uint32_t flags) {
     flags_ = flags;
 
@@ -370,3 +377,5 @@ void IfaceMgr::Iface::setFlags(uint32_t flags) {
 }
 
 }
+
+#endif // if defined(LINUX)