34 #include <boost/array.hpp>
35 #include <boost/static_assert.hpp>
40 #include <linux/rtnetlink.h>
48 BOOST_STATIC_ASSERT(IFLA_MAX>=IFA_MAX);
71 typedef vector<nlmsghdr*> NetlinkMessages;
86 typedef boost::array<struct rtattr*, IFLA_MAX + 1> RTattribPtrs;
88 Netlink() :
fd_(-1), seq_(0), dump_(0) {
89 memset(&local_, 0,
sizeof(
struct sockaddr_nl));
90 memset(&peer_, 0,
sizeof(
struct sockaddr_nl));
98 void rtnl_open_socket();
99 void rtnl_send_request(
int family,
int type);
100 void rtnl_store_reply(NetlinkMessages& storage,
const nlmsghdr* msg);
101 void parse_rtattr(RTattribPtrs& table, rtattr* rta,
int len);
102 void ipaddrs_get(
Iface& iface, NetlinkMessages& addr_info);
103 void rtnl_process_reply(NetlinkMessages&
info);
104 void release_list(NetlinkMessages& messages);
105 void rtnl_close_socket();
116 const static size_t SNDBUF_SIZE = 32768;
119 const static size_t RCVBUF_SIZE = 32768;
124 void Netlink::rtnl_open_socket() {
126 fd_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
131 if (fcntl(
fd_, F_SETFD, FD_CLOEXEC) < 0) {
135 if (setsockopt(
fd_, SOL_SOCKET, SO_SNDBUF, &SNDBUF_SIZE,
sizeof(SNDBUF_SIZE)) < 0) {
139 if (setsockopt(
fd_, SOL_SOCKET, SO_RCVBUF, &RCVBUF_SIZE,
sizeof(RCVBUF_SIZE)) < 0) {
143 local_.nl_family = AF_NETLINK;
144 local_.nl_groups = 0;
150 socklen_t addr_len =
sizeof(local_);
156 if ( (addr_len !=
sizeof(local_)) ||
157 (local_.nl_family != AF_NETLINK) ) {
163 void Netlink::rtnl_close_socket() {
174 void Netlink::rtnl_send_request(
int family,
int type) {
176 nlmsghdr netlink_header;
180 struct sockaddr_nl nladdr;
183 BOOST_STATIC_ASSERT(
sizeof(nlmsghdr) == offsetof(Req,
generic));
185 memset(&nladdr, 0,
sizeof(nladdr));
186 nladdr.nl_family = AF_NETLINK;
202 memset(&req, 0,
sizeof(req));
203 req.netlink_header.nlmsg_len =
sizeof(req);
204 req.netlink_header.nlmsg_type = type;
205 req.netlink_header.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
206 req.netlink_header.nlmsg_pid = 0;
207 req.netlink_header.nlmsg_seq = seq_;
208 req.generic.rtgen_family = family;
210 int status = sendto(
fd_, static_cast<void*>(&req),
sizeof(req), 0,
211 static_cast<struct sockaddr*>(static_cast<void*>(&nladdr)),
216 <<
" bytes over netlink socket.");
228 void Netlink::rtnl_store_reply(NetlinkMessages& storage,
const struct nlmsghdr *msg)
233 struct nlmsghdr*
copy =
reinterpret_cast<struct nlmsghdr*
>(
new char[msg->nlmsg_len]);
234 memcpy(copy, msg, msg->nlmsg_len);
237 storage.push_back(copy);
250 void Netlink::parse_rtattr(RTattribPtrs& table,
struct rtattr* rta,
int len)
252 std::fill(table.begin(), table.end(),
static_cast<struct rtattr*
>(NULL));
259 while (RTA_OK(rta, len)) {
260 if (rta->rta_type < table.size()) {
261 table[rta->rta_type] = rta;
263 rta = RTA_NEXT(rta,len);
280 void Netlink::ipaddrs_get(
Iface& iface, NetlinkMessages& addr_info) {
281 uint8_t addr[V6ADDRESS_LEN];
284 for (NetlinkMessages::const_iterator msg = addr_info.begin();
285 msg != addr_info.end(); ++msg) {
286 ifaddrmsg* ifa =
static_cast<ifaddrmsg*
>(NLMSG_DATA(*msg));
289 if (ifa->ifa_index != iface.
getIndex()) {
293 if ((ifa->ifa_family == AF_INET6) || (ifa->ifa_family == AF_INET)) {
294 std::fill(rta_tb.begin(), rta_tb.end(),
static_cast<rtattr*
>(NULL));
295 parse_rtattr(rta_tb, IFA_RTA(ifa), (*msg)->nlmsg_len - NLMSG_LENGTH(
sizeof(*ifa)));
296 if (!rta_tb[IFA_LOCAL]) {
297 rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
299 if (!rta_tb[IFA_ADDRESS]) {
300 rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
303 memcpy(addr, RTA_DATA(rta_tb[IFLA_ADDRESS]),
304 ifa->ifa_family==AF_INET?V4ADDRESS_LEN:V6ADDRESS_LEN);
305 IOAddress a = IOAddress::fromBytes(ifa->ifa_family, addr);
322 void Netlink::rtnl_process_reply(NetlinkMessages&
info) {
326 memset(&msg, 0,
sizeof(msghdr));
327 msg.msg_name = &nladdr;
328 msg.msg_namelen =
sizeof(nladdr);
332 char buf[RCVBUF_SIZE];
335 iov.iov_len =
sizeof(buf);
337 int status = recvmsg(
fd_, &msg, 0);
340 if (errno == EINTR) {
344 <<
" while processing reply from netlink socket.");
351 nlmsghdr* header =
static_cast<nlmsghdr*
>(
static_cast<void*
>(buf));
352 while (NLMSG_OK(header, status)) {
357 if (nladdr.nl_pid != 0 ||
358 header->nlmsg_pid != local_.nl_pid ||
359 header->nlmsg_seq != dump_) {
360 header = NLMSG_NEXT(header, status);
364 if (header->nlmsg_type == NLMSG_DONE) {
369 if (header->nlmsg_type == NLMSG_ERROR) {
370 nlmsgerr* err =
static_cast<nlmsgerr*
>(NLMSG_DATA(header));
371 if (header->nlmsg_len < NLMSG_LENGTH(
sizeof(
struct nlmsgerr))) {
383 rtnl_store_reply(info, header);
385 header = NLMSG_NEXT(header, status);
387 if (msg.msg_flags & MSG_TRUNC) {
391 isc_throw(
Unexpected,
"Trailing garbage of " << status <<
" bytes received over netlink.");
399 void Netlink::release_list(NetlinkMessages& messages) {
401 for (NetlinkMessages::iterator msg = messages.begin(); msg != messages.end(); ++msg) {
418 void IfaceMgr::detectIfaces() {
420 Netlink::NetlinkMessages link_info;
423 Netlink::NetlinkMessages addr_info;
429 Netlink::RTattribPtrs attribs_table;
430 std::fill(attribs_table.begin(), attribs_table.end(),
431 static_cast<struct rtattr*
>(NULL));
434 nl.rtnl_open_socket();
438 nl.rtnl_send_request(AF_PACKET, RTM_GETLINK);
447 nl.rtnl_process_reply(link_info);
453 nl.rtnl_send_request(AF_UNSPEC, RTM_GETADDR);
458 nl.rtnl_process_reply(addr_info);
461 for (Netlink::NetlinkMessages::iterator msg = link_info.begin();
462 msg != link_info.end(); ++msg) {
464 struct ifinfomsg* interface_info =
static_cast<ifinfomsg*
>(NLMSG_DATA(*msg));
465 int len = (*msg)->nlmsg_len;
466 len -= NLMSG_LENGTH(
sizeof(*interface_info));
467 nl.parse_rtattr(attribs_table, IFLA_RTA(interface_info), len);
472 const char* tmp =
static_cast<const char*
>(RTA_DATA(attribs_table[IFLA_IFNAME]));
473 string iface_name(tmp);
476 if (interface_info->ifi_index < 0) {
479 IfacePtr iface(
new Iface(iface_name, interface_info->ifi_index));
481 iface->
setHWType(interface_info->ifi_type);
482 iface->
setFlags(interface_info->ifi_flags);
485 if (attribs_table[IFLA_ADDRESS]) {
486 iface->
setMac(static_cast<const uint8_t*>(RTA_DATA(attribs_table[IFLA_ADDRESS])),
487 RTA_PAYLOAD(attribs_table[IFLA_ADDRESS]));
494 nl.ipaddrs_get(*iface, addr_info);
500 nl.release_list(link_info);
501 nl.release_list(addr_info);
506 nl.release_list(link_info);
507 nl.release_list(addr_info);
516 void Iface::setFlags(uint64_t flags) {
519 flag_loopback_ = flags & IFF_LOOPBACK;
520 flag_up_ = flags & IFF_UP;
521 flag_running_ = flags & IFF_RUNNING;
522 flag_multicast_ = flags & IFF_MULTICAST;
523 flag_broadcast_ = flags & IFF_BROADCAST;
527 IfaceMgr::setMatchingPacketFilter(
const bool direct_response_desired) {
528 if (direct_response_desired) {
538 IfaceMgr::openMulticastSocket(
Iface& iface,
548 sock = openSocket(iface.
getName(), addr, port,
553 "Failed to open link-local socket on "
554 " interface " << iface.
getName() <<
": "
581 "Failed to open multicast socket on"
582 " interface " << iface.
getName()
583 <<
", reason: " << ex.
what());
592 IfaceMgr::openSocket6(
Iface& iface,
const IOAddress& addr, uint16_t port,
593 const bool join_multicast) {
595 SocketInfo info = packet_filter6_->openSocket(iface, addr, port,
605 #endif // if defined(LINUX)
Packet handling class using Linux Packet Filtering.
IfaceMgr exception thrown thrown when socket opening or configuration failed.
void setFlags(uint64_t flags)
Sets flag_*_ fields based on bitmask value returned by OS.
void addSocket(const SocketInfo &sock)
Adds socket descriptor to an interface.
bool delSocket(uint16_t sockfd)
Closes socket.
void setHWType(uint16_t type)
Sets up hardware type of the interface.
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
uint32_t getIndex() const
Returns interface index.
std::function< void(const std::string &errmsg)> IfaceMgrErrorMsgCallback
This type describes the callback function invoked when error occurs in the IfaceMgr.
Packet handling class using AF_INET socket family.
Represents a single network interface.
boost::shared_ptr< PktFilter > PktFilterPtr
Pointer to a PktFilter object.
#define ALL_DHCP_RELAY_AGENTS_AND_SERVERS
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
bool flag_multicast_
Flag specifies if selected interface is multicast capable.
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
A generic exception that is thrown when an unexpected error condition occurs.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
std::string getName() const
Returns interface name.
This is a base class for exceptions thrown from the DNS library module.
Defines the logger used by the top-level component of kea-dhcp-ddns.
#define IFACEMGR_ERROR(ex_type, handler, stream)
A macro which handles an error in IfaceMgr.
const struct sockaddr * convertSockAddr(const SAType *sa)
void addAddress(const isc::asiolink::IOAddress &addr)
Adds an address to an interface.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
The IOAddress class represents an IP addresses (version agnostic)
Holds information about socket.
void setMac(const uint8_t *mac, size_t macLen)
Sets MAC address of the interface.