IBR-DTNSuite
0.8
|
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 */