34#include <boost/array.hpp>
35#include <boost/static_assert.hpp>
40#include <linux/rtnetlink.h>
48BOOST_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();
116const static size_t SNDBUF_SIZE = 32768;
119const static size_t RCVBUF_SIZE = 32768;
124void 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) ) {
163void Netlink::rtnl_close_socket() {
174void 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.");
228void Netlink::rtnl_store_reply(NetlinkMessages& storage,
const struct nlmsghdr *msg) {
232 struct nlmsghdr*
copy =
reinterpret_cast<struct nlmsghdr*
>(
new char[msg->nlmsg_len]);
233 memcpy(copy, msg, msg->nlmsg_len);
236 storage.push_back(copy);
249void Netlink::parse_rtattr(RTattribPtrs& table,
struct rtattr* rta,
int len) {
250 std::fill(table.begin(), table.end(),
static_cast<struct rtattr*
>(NULL));
257 while (RTA_OK(rta, len)) {
258 if (rta->rta_type < table.size()) {
259 table[rta->rta_type] = rta;
261 rta = RTA_NEXT(rta,len);
278void Netlink::ipaddrs_get(
Iface& iface, NetlinkMessages& addr_info) {
279 uint8_t addr[V6ADDRESS_LEN];
282 for (
auto const& msg : addr_info) {
283 ifaddrmsg* ifa =
static_cast<ifaddrmsg*
>(NLMSG_DATA(msg));
286 if (ifa->ifa_index != iface.getIndex()) {
290 if ((ifa->ifa_family == AF_INET6) || (ifa->ifa_family == AF_INET)) {
291 std::fill(rta_tb.begin(), rta_tb.end(),
static_cast<rtattr*
>(NULL));
292 parse_rtattr(rta_tb, IFA_RTA(ifa), msg->nlmsg_len - NLMSG_LENGTH(
sizeof(*ifa)));
293 if (!rta_tb[IFA_LOCAL]) {
294 rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
296 if (!rta_tb[IFA_ADDRESS]) {
297 rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
300 memcpy(addr, RTA_DATA(rta_tb[IFLA_ADDRESS]),
301 ifa->ifa_family==AF_INET?V4ADDRESS_LEN:V6ADDRESS_LEN);
302 IOAddress a = IOAddress::fromBytes(ifa->ifa_family, addr);
319void Netlink::rtnl_process_reply(NetlinkMessages& info) {
323 memset(&msg, 0,
sizeof(msghdr));
324 msg.msg_name = &nladdr;
325 msg.msg_namelen =
sizeof(nladdr);
329 char buf[RCVBUF_SIZE];
332 iov.iov_len =
sizeof(buf);
334 int status = recvmsg(fd_, &msg, 0);
337 if (errno == EINTR) {
341 <<
" while processing reply from netlink socket.");
348 nlmsghdr* header =
static_cast<nlmsghdr*
>(
static_cast<void*
>(buf));
349 while (NLMSG_OK(header, status)) {
354 if (nladdr.nl_pid != 0 ||
355 header->nlmsg_pid != local_.nl_pid ||
356 header->nlmsg_seq != dump_) {
357 header = NLMSG_NEXT(header, status);
361 if (header->nlmsg_type == NLMSG_DONE) {
366 if (header->nlmsg_type == NLMSG_ERROR) {
367 nlmsgerr* err =
static_cast<nlmsgerr*
>(NLMSG_DATA(header));
368 if (header->nlmsg_len < NLMSG_LENGTH(
sizeof(
struct nlmsgerr))) {
380 rtnl_store_reply(info, header);
382 header = NLMSG_NEXT(header, status);
384 if (msg.msg_flags & MSG_TRUNC) {
388 isc_throw(
Unexpected,
"Trailing garbage of " << status <<
" bytes received over netlink.");
396void Netlink::release_list(NetlinkMessages& messages) {
398 for (
auto const& msg : messages) {
415void IfaceMgr::detectIfaces(
bool update_only) {
416 if (detect_callback_) {
417 if (!detect_callback_(update_only)) {
423 Netlink::NetlinkMessages link_info;
426 Netlink::NetlinkMessages addr_info;
432 Netlink::RTattribPtrs attribs_table;
433 std::fill(attribs_table.begin(), attribs_table.end(),
434 static_cast<struct rtattr*
>(NULL));
437 nl.rtnl_open_socket();
441 nl.rtnl_send_request(AF_PACKET, RTM_GETLINK);
450 nl.rtnl_process_reply(link_info);
456 nl.rtnl_send_request(AF_UNSPEC, RTM_GETADDR);
461 nl.rtnl_process_reply(addr_info);
464 for (
auto const& msg : link_info) {
466 struct ifinfomsg* interface_info =
static_cast<ifinfomsg*
>(NLMSG_DATA(msg));
467 int len = msg->nlmsg_len;
468 len -= NLMSG_LENGTH(
sizeof(*interface_info));
469 nl.parse_rtattr(attribs_table, IFLA_RTA(interface_info), len);
474 const char* tmp =
static_cast<const char*
>(RTA_DATA(attribs_table[IFLA_IFNAME]));
475 string iface_name(tmp);
478 if (interface_info->ifi_index < 0) {
485 iface = getIface(iface_name);
492 iface.reset(
new Iface(iface_name, interface_info->ifi_index));
495 iface->setHWType(interface_info->ifi_type);
496 iface->setFlags(interface_info->ifi_flags);
499 if (attribs_table[IFLA_ADDRESS]) {
500 iface->setMac(
static_cast<const uint8_t*
>(RTA_DATA(attribs_table[IFLA_ADDRESS])),
501 RTA_PAYLOAD(attribs_table[IFLA_ADDRESS]));
507 nl.ipaddrs_get(*iface, addr_info);
515 nl.release_list(link_info);
516 nl.release_list(addr_info);
521 nl.release_list(link_info);
522 nl.release_list(addr_info);
531void Iface::setFlags(uint64_t flags) {
534 flag_loopback_ = flags & IFF_LOOPBACK;
535 flag_up_ = flags & IFF_UP;
536 flag_running_ = flags & IFF_RUNNING;
537 flag_multicast_ = flags & IFF_MULTICAST;
538 flag_broadcast_ = flags & IFF_BROADCAST;
542IfaceMgr::setMatchingPacketFilter(
const bool direct_response_desired) {
543 if (direct_response_desired) {
553IfaceMgr::openMulticastSocket(
Iface& iface,
556 IfaceMgrErrorMsgCallback error_handler) {
563 sock = openSocket(iface.getName(), addr, port, iface.flag_multicast_);
567 "Failed to open link-local socket on "
568 "interface " << iface.getName() <<
": "
583 if (iface.flag_multicast_) {
585 openSocket(iface.getName(),
593 iface.delSocket(sock);
595 "Failed to open multicast socket on"
596 " interface " << iface.getName()
597 <<
", reason: " << ex.
what());
606IfaceMgr::openSocket6(
Iface& iface,
const IOAddress& addr, uint16_t port,
607 const bool join_multicast) {
611 iface.addSocket(info);
613 return (
info.sockfd_);
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
The IOAddress class represents an IP addresses (version agnostic)
Represents a single network interface.
Packet handling class using AF_INET socket family.
Packet handling class using Linux Packet Filtering.
IfaceMgr exception thrown thrown when socket opening or configuration failed.
#define ALL_DHCP_RELAY_AGENTS_AND_SERVERS
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define IFACEMGR_ERROR(ex_type, handler, iface, stream)
A macro which handles an error in IfaceMgr.
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
boost::shared_ptr< PktFilter > PktFilterPtr
Pointer to a PktFilter object.
boost::shared_ptr< Iface > IfacePtr
Type definition for the pointer to an Iface object.
const struct sockaddr * convertSockAddr(const SAType *sa)
Defines the logger used by the top-level component of kea-lfc.
Holds information about socket.