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