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