00001
00002
00003
00004
00005
00006
00007
00008 #include "ibrcommon/net/NetLinkManager.h"
00009 #include "ibrcommon/thread/MutexLock.h"
00010 #include "ibrcommon/Logger.h"
00011
00012 #include <netlink/socket.h>
00013 #include <netlink/route/rtnl.h>
00014 #include <netlink/route/link.h>
00015 #include <netlink/route/addr.h>
00016 #include <netlink/genl/genl.h>
00017 #include <netlink/genl/ctrl.h>
00018
00019 #include <netdb.h>
00020 #include <sys/socket.h>
00021 #include <sys/types.h>
00022 #include <netinet/tcp.h>
00023 #include <sys/un.h>
00024 #include <errno.h>
00025 #include <string.h>
00026 #include <fcntl.h>
00027 #include <signal.h>
00028 #include <arpa/inet.h>
00029
00030 #include <iostream>
00031 #include <sstream>
00032
00033 namespace ibrcommon
00034 {
00035 NetLinkManager::NetLinkManager()
00036 : _initialized(false), _sock(NULL)
00037 {
00038 ibrcommon::MutexLock l(_call_mutex);
00039
00040 _handle = nl_handle_alloc();
00041 nl_connect(_handle, NETLINK_ROUTE);
00042
00043 _link_cache = rtnl_link_alloc_cache(_handle);
00044 _addr_cache = rtnl_addr_alloc_cache(_handle);
00045
00046 _initialized = true;
00047
00048
00049 _sock = new ibrcommon::vsocket();
00050 }
00051
00052 NetLinkManager::~NetLinkManager()
00053 {
00054 stop();
00055 join();
00056
00057
00058 _sock = new ibrcommon::vsocket();
00059
00060 nl_close(_handle);
00061 nl_cache_free(_addr_cache);
00062 nl_cache_free(_link_cache);
00063 nl_handle_destroy(_handle);
00064 }
00065
00066 void add_addr_to_list(struct nl_object *obj, void *data)
00067 {
00068 char buf[INET6_ADDRSTRLEN+5];
00069 std::list<vaddress> *list = static_cast<std::list<vaddress>*>(data);
00070
00071 struct nl_addr *naddr = rtnl_addr_get_local((struct rtnl_addr *) obj);
00072 int ifindex = 0;
00073 int scope = rtnl_addr_get_scope((struct rtnl_addr *) obj);
00074
00075 if (scope == rtnl_str2scope("link"))
00076 ifindex = rtnl_addr_get_ifindex((struct rtnl_addr *) obj);
00077
00078 if (naddr)
00079 {
00080 int family = nl_addr_get_family(naddr);
00081 nl_addr2str( naddr, buf, sizeof( buf ) );
00082 vaddress vaddr(vaddress::Family(family), std::string(buf), ifindex, false);
00083 list->push_back( vaddr );
00084 }
00085
00086 struct nl_addr *baddr = rtnl_addr_get_broadcast((struct rtnl_addr *) obj);
00087
00088 if (baddr)
00089 {
00090 int family = nl_addr_get_family(baddr);
00091 nl_addr2str( baddr, buf, sizeof( buf ) );
00092 vaddress vaddr(vaddress::Family(family), std::string(buf), ifindex, true);
00093 list->push_back( vaddr );
00094 }
00095 }
00096
00097 bool NetLinkManager::__cancellation()
00098 {
00099 ibrcommon::MutexLock l(_call_mutex);
00100 _initialized = false;
00101 ibrcommon::interrupt(*_sock, *this);
00102
00103 return true;
00104 }
00105
00106 void NetLinkManager::run()
00107 {
00108 Thread::enable_interruption();
00109
00110 struct nl_handle *handle = nl_handle_alloc();
00111 nl_connect(handle, NETLINK_ROUTE);
00112
00113
00114 nl_socket_add_membership(handle, RTMGRP_IPV6_IFADDR);
00115 nl_socket_add_membership(handle, RTMGRP_IPV4_IFADDR);
00116 nl_socket_add_membership(handle, RTMGRP_LINK);
00117
00118
00119 _sock->add(nl_socket_get_fd(handle));
00120
00121 try {
00122 while (_initialized)
00123 {
00124 std::list<int> fds;
00125 ibrcommon::select(*_sock, fds, NULL);
00126 int fd = fds.front();
00127
00128 std::map<int, std::string> attr = read_nlmsg(fd);
00129 std::string ifname(attr[IFLA_IFNAME]);
00130 vinterface iface(ifname.substr(0, ifname.length() - 1));
00131
00132
00133 ibrcommon::MutexLock l(_listener_mutex);
00134 const std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00135
00136 for (std::set<LinkManager::EventCallback* >::iterator iter = ss.begin(); iter != ss.end(); iter++)
00137 {
00138 IBRCOMMON_LOGGER_DEBUG(10) << "one socket has subscribed action on interface: " << iface.toString() << IBRCOMMON_LOGGER_ENDL;
00139 }
00140 }
00141 } catch (const vsocket_exception&) {
00142
00143 }
00144
00145 nl_close(handle);
00146 nl_handle_destroy(handle);
00147 }
00148
00149 const std::list<vaddress> NetLinkManager::getAddressList(const vinterface &interface, const vaddress::Family f)
00150 {
00151 ibrcommon::MutexLock l(_call_mutex);
00152
00153 std::list<vaddress> addresses;
00154
00155 struct rtnl_addr *filter = rtnl_addr_alloc();
00156 const std::string i = interface.toString();
00157 rtnl_addr_set_ifindex(filter, rtnl_link_name2i(_link_cache, i.c_str()));
00158
00159 if (f == vaddress::VADDRESS_UNSPEC)
00160 {
00161 rtnl_addr_set_family(filter, AF_INET6);
00162 nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00163 add_addr_to_list, &addresses);
00164
00165 rtnl_addr_set_family(filter, AF_INET);
00166 nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00167 add_addr_to_list, &addresses);
00168 }
00169 else
00170 {
00171 rtnl_addr_set_family(filter, f);
00172 nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00173 add_addr_to_list, &addresses);
00174 }
00175
00176 rtnl_addr_put(filter);
00177
00178 return addresses;
00179 }
00180
00181 const std::string NetLinkManager::getInterface(const int ifindex) const
00182 {
00183 char buf[256];
00184 rtnl_link_i2name(_link_cache, ifindex, (char*)&buf, sizeof buf);
00185 return std::string((char*)&buf);
00186 }
00187
00188 std::map<int, std::string> NetLinkManager::read_nlmsg(int fd)
00189 {
00190 char buf[1024];
00191 int left;
00192 struct sockaddr_nl from;
00193 socklen_t fromlen;
00194 struct nlmsghdr *h;
00195
00196 fromlen = sizeof(from);
00197
00198
00199 left = recvfrom(fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *) &from, &fromlen);
00200
00201 if (left < 0 && errno != EINTR && errno != EAGAIN)
00202 {
00203 throw parse_exception("recvfrom(netlink) failed");
00204 }
00205
00206
00207 h = (struct nlmsghdr *) buf;
00208
00209 std::map<int, std::string> attrlist;
00210
00211 while (left >= sizeof(*h))
00212 {
00213 int len, plen;
00214
00215 len = h->nlmsg_len;
00216
00217 plen = len - sizeof(*h);
00218
00219 if (len > left || plen < 0)
00220 {
00221 throw parse_exception("Malformed netlink message");
00222 }
00223
00224 if (h->nlmsg_type == RTM_BASE)
00225 {
00226 struct ifinfomsg *ifi;
00227 int attrlen, nlmsg_len, rta_len;
00228 struct rtattr * attr;
00229
00230 if (len < sizeof(*ifi)) return attrlist;
00231
00232 ifi = (struct ifinfomsg *)NLMSG_DATA(h);
00233
00234 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
00235
00236 attrlen = h->nlmsg_len - nlmsg_len;
00237 if (attrlen < 0) return attrlist;
00238
00239 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
00240
00241 rta_len = RTA_ALIGN(sizeof(struct rtattr));
00242 while (RTA_OK(attr, attrlen))
00243 {
00244 size_t rta_length = RTA_PAYLOAD(attr);
00245 std::string payload((char*)RTA_DATA(attr), rta_length);
00246
00247 attrlist[attr->rta_type] = payload;
00248 attr = RTA_NEXT(attr, attrlen);
00249 }
00250 }
00251
00252 len = NLMSG_ALIGN(len);
00253 left -= len;
00254 h = (struct nlmsghdr *) ((char *) h + len);
00255 }
00256
00257 return attrlist;
00258 }
00259
00260 void NetLinkManager::registerInterfaceEvent(const vinterface &iface, LinkManager::EventCallback *cb)
00261 {
00262 if (cb == NULL) return;
00263 ibrcommon::MutexLock l(_listener_mutex);
00264
00265 std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00266 ss.insert(cb);
00267 }
00268
00269 void NetLinkManager::unregisterInterfaceEvent(const vinterface &iface, LinkManager::EventCallback *cb)
00270 {
00271 if (cb == NULL) return;
00272 ibrcommon::MutexLock l(_listener_mutex);
00273
00274 std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00275
00276 ss.erase(cb);
00277
00278 if (ss.empty())
00279 {
00280 _listener.erase(iface);
00281 }
00282 }
00283
00284 void NetLinkManager::unregisterAllEvents(LinkManager::EventCallback *cb)
00285 {
00286 if (cb == NULL) return;
00287
00288 try {
00289 ibrcommon::MutexLock l(_listener_mutex);
00290
00291 for (std::map<vinterface, std::set<LinkManager::EventCallback* > >::iterator iter = _listener.begin(); iter != _listener.end(); iter++)
00292 {
00293 std::set<LinkManager::EventCallback* > &ss = iter->second;
00294 ss.erase(cb);
00295 }
00296 } catch (const ibrcommon::MutexException&) {
00297
00298
00299 }
00300 }
00301 }