IBR-DTNSuite  0.8
ibrcommon/ibrcommon/net/NetLink3Manager.cpp
Go to the documentation of this file.
00001 /*
00002  * NetLink3Manager.cpp
00003  *
00004  *  Created on: 17.10.2011
00005  *      Author: morgenro
00006  */
00007 
00008 #include "ibrcommon/net/NetLink3Manager.h"
00009 #include "ibrcommon/net/vsocket.h"
00010 #include "ibrcommon/Logger.h"
00011 
00012 #include <netlink/netlink.h>
00013 #include <netlink/route/link.h>
00014 #include <netlink/route/addr.h>
00015 #include <netlink/route/rtnl.h>
00016 #include <netlink/socket.h>
00017 #include <netlink/msg.h>
00018 //#include <net/if.h>
00019 #include <string.h>
00020 
00021 namespace ibrcommon
00022 {
00023         static int nl3_callback(struct nl_msg *msg, void *arg)
00024         {
00025                 NetLink3Manager *m = static_cast<NetLink3Manager *>(arg);
00026                 NetLink3ManagerEvent evt(msg);
00027                 m->callback(evt);
00028                 return 0;
00029         }
00030 
00031         void add_addr_to_list(struct nl_object *obj, void *data)
00032         {
00033                 char buf[INET6_ADDRSTRLEN+5];
00034                 std::list<vaddress> *list = static_cast<std::list<vaddress>*>(data);
00035 
00036                 struct nl_addr *naddr = rtnl_addr_get_local((struct rtnl_addr *) obj);
00037                 int ifindex = 0;
00038                 int scope = rtnl_addr_get_scope((struct rtnl_addr *) obj);
00039 
00040                 if (scope == rtnl_str2scope("link"))
00041                         ifindex = rtnl_addr_get_ifindex((struct rtnl_addr *) obj);
00042 
00043                 if (naddr)
00044                 {
00045                         int family = nl_addr_get_family(naddr);
00046                         nl_addr2str( naddr, buf, sizeof( buf ) );
00047                         vaddress vaddr(vaddress::Family(family), vaddress::strip_netmask(std::string(buf)), ifindex, false);
00048                         list->push_back( vaddr );
00049                 }
00050 
00051                 struct nl_addr *baddr = rtnl_addr_get_broadcast((struct rtnl_addr *) obj);
00052 
00053                 if (baddr)
00054                 {
00055                         int family = nl_addr_get_family(baddr);
00056                         nl_addr2str( baddr, buf, sizeof( buf ) );
00057                         vaddress vaddr(vaddress::Family(family), vaddress::strip_netmask(std::string(buf)), ifindex, true);
00058                         list->push_back( vaddr );
00059                 }
00060         }
00061 
00062         NetLink3Manager::NetLink3Manager()
00063          : _refresh_cache(false), _running(true), _sock(NULL)
00064         {
00065                 // initialize the sockets
00066                 _nl_notify_sock = nl_socket_alloc();
00067                 _nl_query_sock = nl_socket_alloc();
00068 
00069                 // disable seq check for notify socket
00070                 nl_socket_disable_seq_check(_nl_notify_sock);
00071 
00072                 // define callback method
00073                 nl_socket_modify_cb(_nl_notify_sock, NL_CB_VALID, NL_CB_CUSTOM, nl3_callback, this);
00074 
00075                 // connect to routing netlink protocol
00076                 nl_connect(_nl_notify_sock, NETLINK_ROUTE);
00077                 nl_connect(_nl_query_sock, NETLINK_ROUTE);
00078 
00079                 // init route messages
00080                 nl_socket_add_memberships(_nl_notify_sock, RTNLGRP_IPV4_IFADDR);
00081 
00082 //              IPv6 requires further support in the parsing procedures!
00083 //              nl_socket_add_membership(_nl_notify_sock, RTNLGRP_IPV6_IFADDR);
00084                 nl_socket_add_memberships(_nl_notify_sock, RTNLGRP_LINK);
00085 
00086                 // create a cache for the links
00087                 if (rtnl_link_alloc_cache(_nl_query_sock, AF_UNSPEC, &_link_cache) < 0)
00088                 {
00089                         nl_socket_free(_nl_notify_sock);
00090                         nl_socket_free(_nl_query_sock);
00091                         // error
00092                         throw ibrcommon::vsocket_exception("netlink cache allocation failed");
00093                 }
00094 
00095                 // create a cache for addresses
00096                 if (rtnl_addr_alloc_cache(_nl_query_sock, &_addr_cache) < 0)
00097                 {
00098                         nl_socket_free(_nl_notify_sock);
00099                         nl_socket_free(_nl_query_sock);
00100                         // error
00101                         nl_cache_free(_link_cache);
00102                         _link_cache = NULL;
00103                         throw ibrcommon::vsocket_exception("netlink cache allocation failed");
00104                 }
00105 
00106                 // create a new socket for the netlink interface
00107                 _sock = new ibrcommon::vsocket();
00108         }
00109 
00110         NetLink3Manager::~NetLink3Manager()
00111         {
00112                 stop();
00113                 join();
00114 
00115                 // destroy the socket for the netlink interface
00116                 delete _sock;
00117 
00118                 nl_cache_free(_addr_cache);
00119                 nl_cache_free(_link_cache);
00120 
00121                 nl_socket_free(_nl_notify_sock);
00122                 nl_socket_free(_nl_query_sock);
00123         }
00124 
00125         const std::string NetLink3Manager::getInterface(int index) const
00126         {
00127                 char buf[256];
00128                 rtnl_link_i2name(_link_cache, index, (char*)&buf, sizeof buf);
00129                 return std::string((char*)&buf);
00130         }
00131 
00132         const std::list<vaddress> NetLink3Manager::getAddressList(const vinterface &iface, const vaddress::Family f)
00133         {
00134                 ibrcommon::MutexLock l(_call_mutex);
00135 
00136                 if (_refresh_cache)
00137                 {
00138                         nl_cache_free(_addr_cache);
00139                         nl_cache_free(_link_cache);
00140 
00141                         // create a cache for the links
00142                         if (rtnl_link_alloc_cache(_nl_query_sock, AF_UNSPEC, &_link_cache) < 0)
00143                         {
00144                                 // error
00145                                 throw ibrcommon::vsocket_exception("netlink cache allocation failed");
00146                         }
00147 
00148                         // create a cache for addresses
00149                         if (rtnl_addr_alloc_cache(_nl_query_sock, &_addr_cache) < 0)
00150                         {
00151                                 // error
00152                                 nl_cache_free(_link_cache);
00153                                 _link_cache = NULL;
00154                                 throw ibrcommon::vsocket_exception("netlink cache allocation failed");
00155                         }
00156 
00157                         // mark the cache as refreshed
00158                         _refresh_cache = false;
00159                 }
00160 
00161                 std::list<vaddress> addresses;
00162 
00163                 struct rtnl_addr *filter = rtnl_addr_alloc();
00164                 const std::string i = iface.toString();
00165                 rtnl_addr_set_ifindex(filter, rtnl_link_name2i(_link_cache, i.c_str()));
00166 
00167                 if (f == vaddress::VADDRESS_UNSPEC)
00168                 {
00169                         rtnl_addr_set_family(filter, AF_INET6);
00170                         nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00171                                                                         add_addr_to_list, &addresses);
00172 
00173                         rtnl_addr_set_family(filter, AF_INET);
00174                         nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00175                                                                         add_addr_to_list, &addresses);
00176                 }
00177                 else
00178                 {
00179                         rtnl_addr_set_family(filter, f);
00180                         nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00181                                                                         add_addr_to_list, &addresses);
00182                 }
00183 
00184                 rtnl_addr_put(filter);
00185 
00186                 return addresses;
00187         }
00188 
00189         void NetLink3Manager::callback(const NetLink3ManagerEvent &lme)
00190         {
00191                 // ignore if the event is unknown
00192                 if (lme.getType() == LinkManagerEvent::EVENT_UNKOWN) return;
00193 
00194                 // ignore if this is an wireless extension event
00195                 if (lme.isWirelessExtension()) return;
00196 
00197                 // need to refresh the cache
00198                 {
00199                         ibrcommon::MutexLock l(_call_mutex);
00200                         _refresh_cache = true;
00201                 }
00202 
00203                 // print out some debugging
00204                 IBRCOMMON_LOGGER_DEBUG(10) << lme.toString() << IBRCOMMON_LOGGER_ENDL;
00205 
00206                 // notify all subscribers about this event
00207                 raiseEvent(lme);
00208         }
00209 
00210         void NetLink3Manager::run()
00211         {
00212                 // add netlink fd to vsocket
00213                 _sock->add(nl_socket_get_fd(_nl_notify_sock));
00214 
00215                 try {
00216                         while (_running)
00217                         {
00218                                 std::list<int> fds;
00219                                 _sock->select(fds, NULL);
00220 
00221                                 nl_recvmsgs_default(_nl_notify_sock);
00222                         }
00223                 } catch (const vsocket_exception&) {
00224                         // stopped / interrupted
00225                         IBRCOMMON_LOGGER(error) << "NetLink connection stopped" << IBRCOMMON_LOGGER_ENDL;
00226                 }
00227         }
00228 
00229         void NetLink3Manager::__cancellation()
00230         {
00231                 _running = false;
00232                 _sock->close();
00233         }
00234 
00236         NetLink3ManagerEvent::NetLink3ManagerEvent(struct nl_msg *msg)
00237          : _type(EVENT_UNKOWN), _state(0), _wireless(false)
00238         {
00239                 int attrlen, nlmsg_len, rta_len, rtl;
00240                 struct rtattr *attr;
00241                 struct rtattr *rth;
00242                 struct ifaddrmsg *ifa;
00243                 struct ifinfomsg *ifi;
00244                 struct nlmsghdr *nlh;
00245 
00246                 // cast netlink message
00247                 nlh = nlmsg_hdr(msg);
00248 
00249                 switch (nlh->nlmsg_type)
00250                 {
00251                         case RTM_BASE:
00252                         {
00253                                 ifi = (struct ifinfomsg *) NLMSG_DATA(nlh);
00254 
00255                                 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
00256                                 attrlen = nlh->nlmsg_len - nlmsg_len;
00257 
00258                                 if (attrlen < 0) break;
00259 
00260                                 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
00261 
00262                                 rta_len = RTA_ALIGN(sizeof(struct rtattr));
00263                                 while (RTA_OK(attr, attrlen))
00264                                 {
00265                                         size_t rta_length = RTA_PAYLOAD(attr);
00266 
00267                                         switch (attr->rta_type)
00268                                         {
00269                                         case IFLA_IFNAME:
00270                                                 _interface = ibrcommon::vinterface( std::string((char*)RTA_DATA(attr), rta_length) );
00271                                                 _type = EVENT_LINK_STATE;
00272                                                 break;
00273 
00274                                         case IFLA_OPERSTATE:
00275                                         {
00276                                                 char s;
00277                                                 ::memcpy(&s, (char*)RTA_DATA(attr), 1);
00278                                                 _state = s;
00279                                                 break;
00280                                         }
00281 
00282                                         case IFLA_WIRELESS:
00283                                                 _wireless = true;
00284                                                 break;
00285 
00286                                         default:
00287                                                 _attributes[attr->rta_type] = std::string((char*)RTA_DATA(attr), rta_length);
00288                                                 break;
00289                                         }
00290 
00291                                         attr = RTA_NEXT(attr, attrlen);
00292                                 }
00293                                 break;
00294                         }
00295 
00296                         case RTM_NEWADDR:
00297                         {
00298                                 ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
00299                                 rth = IFA_RTA(ifa);
00300                                 rtl = IFA_PAYLOAD(nlh);
00301 
00302                                 // parse all attributes
00303                                 while (rtl && RTA_OK(rth, rtl))
00304                                 {
00305                                         switch (rth->rta_type)
00306                                         {
00307                                                 // local address
00308                                                 case IFA_LOCAL:
00309                                                 {
00310                                                         char address[256];
00311 
00312                                                         uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth)));
00313                                                         sprintf(address, "%d.%d.%d.%d", (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff);
00314 
00315                                                         _address = ibrcommon::vaddress(ibrcommon::vaddress::VADDRESS_INET, std::string(address));
00316                                                         _type = EVENT_ADDRESS_ADDED;
00317                                                         break;
00318                                                 }
00319 
00320                                                 // interface name
00321                                                 case IFA_LABEL:
00322                                                 {
00323                                                         //char name[IFNAMSIZ];
00324                                                         char *name = (char *)RTA_DATA(rth);
00325                                                         _interface = ibrcommon::vinterface(name);
00326                                                         break;
00327                                                 }
00328                                         }
00329                                         rth = RTA_NEXT(rth, rtl);
00330                                 }
00331                                 break;
00332                         }
00333 
00334                         case RTM_DELADDR:
00335                         {
00336                                 ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
00337                                 rth = IFA_RTA(ifa);
00338                                 rtl = IFA_PAYLOAD(nlh);
00339 
00340                                 // parse all attributes
00341                                 while (rtl && RTA_OK(rth, rtl))
00342                                 {
00343                                         switch (rth->rta_type)
00344                                         {
00345                                                 // local address
00346                                                 case IFA_LOCAL:
00347                                                 {
00348                                                         char address[256];
00349 
00350                                                         uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth)));
00351                                                         sprintf(address, "%d.%d.%d.%d", (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff);
00352 
00353                                                         _address = ibrcommon::vaddress(ibrcommon::vaddress::VADDRESS_INET, std::string(address));
00354                                                         _type = EVENT_ADDRESS_REMOVED;
00355                                                         break;
00356                                                 }
00357 
00358                                                 // interface name
00359                                                 case IFA_LABEL:
00360                                                 {
00361                                                         //char name[IFNAMSIZ];
00362                                                         char *name = (char *)RTA_DATA(rth);
00363                                                         _interface = ibrcommon::vinterface(name);
00364                                                         break;
00365                                                 }
00366                                         }
00367                                         rth = RTA_NEXT(rth, rtl);
00368                                 }
00369                                 break;
00370                         }
00371 
00372                         default:
00373                                 IBRCOMMON_LOGGER_DEBUG(10) << "unknown netlink type received: " << nlh->nlmsg_type << IBRCOMMON_LOGGER_ENDL;
00374                                 break;
00375                 }
00376         }
00377 
00378         NetLink3ManagerEvent::~NetLink3ManagerEvent()
00379         {
00380         }
00381 
00382         const ibrcommon::vinterface& NetLink3ManagerEvent::getInterface() const
00383         {
00384                 return _interface;
00385         }
00386 
00387         const ibrcommon::vaddress& NetLink3ManagerEvent::getAddress() const
00388         {
00389                 return _address;
00390         }
00391 
00392         unsigned int NetLink3ManagerEvent::getState() const
00393         {
00394                 return _state;
00395         }
00396 
00397         bool NetLink3ManagerEvent::isWirelessExtension() const
00398         {
00399                 return _wireless;
00400         }
00401 
00402         LinkManagerEvent::EventType NetLink3ManagerEvent::getType() const
00403         {
00404                 return _type;
00405         }
00406 
00407         const std::string NetLink3ManagerEvent::toString() const
00408         {
00409                 std::stringstream ss;
00410                 ss << "NetLinkManagerEvent on " << getInterface().toString() << "; Type: " << getType();
00411 
00412                 switch (getType())
00413                 {
00414                 case EVENT_LINK_STATE:
00415                         ss << "; State: " << getState();
00416                         break;
00417 
00418                 case EVENT_ADDRESS_ADDED:
00419                         ss << "; Address added: " << getAddress().toString();
00420                         break;
00421 
00422                 case EVENT_ADDRESS_REMOVED:
00423                         ss << "; Address removed: " << getAddress().toString();
00424                         break;
00425 
00426                 default:
00427                         break;
00428                 };
00429 
00430                 return ss.str();
00431         }
00432 
00433         void NetLink3ManagerEvent::debug() const
00434         {
00435 //              for (std::map<int, std::string>::const_iterator iter = attr.begin(); iter != attr.end(); iter++)
00436 //              {
00437 //                      std::stringstream ss;
00438 //                      const std::string &value = (*iter).second;
00439 //
00440 //                      for (std::string::const_iterator si = value.begin(); si != value.end(); si++)
00441 //                      {
00442 //                              const char &c = (*si);
00443 //                              ss << std::hex << "0x" << (int)c << " ";
00444 //                      }
00445 //
00446 //                      IBRCOMMON_LOGGER_DEBUG(10) << (*iter).first << ": " << ss.str() << IBRCOMMON_LOGGER_ENDL;
00447 //              }
00448         }
00449 } /* namespace ibrcommon */