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);
 
  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) {
 
  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);
 
  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;
 
  543    if (direct_response_desired) {
 
  553IfaceMgr::openMulticastSocket(
Iface& iface,
 
  567                       "Failed to open link-local socket on " 
  568                       "interface " << iface.
getName() << 
": " 
  595                           "Failed to open multicast socket on" 
  596                           " interface " << iface.
getName()
 
  597                           << 
", reason: " << ex.
what());
 
  607                      const bool join_multicast) {
 
  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)
static IOAddress fromBytes(short family, const uint8_t *data)
Creates an address from over wire data.
void detectIfaces(bool update_only=false)
Detects network interfaces.
int openSocket6(Iface &iface, const isc::asiolink::IOAddress &addr, uint16_t port, const bool join_multicast)
Opens IPv6 socket.
void setMatchingPacketFilter(const bool direct_response_desired=false)
Set Packet Filter object to handle send/receive packets.
Represents a single network interface.
bool flag_multicast_
Flag specifies if selected interface is multicast capable.
std::string getName() const
Returns interface name.
void setFlags(uint64_t flags)
Sets flag_*_ fields based on bitmask value returned by OS.
unsigned int getIndex() const
Returns interface index.
bool delSocket(uint16_t sockfd)
Closes socket.
void addAddress(const isc::asiolink::IOAddress &addr)
Adds an address to an interface.
void addSocket(const SocketInfo &sock)
Adds socket descriptor to an interface.
void setHWType(uint16_t type)
Sets up hardware type of the 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.
std::function< void(const std::string &errmsg)> IfaceMgrErrorMsgCallback
This type describes the callback function invoked when error occurs in the IfaceMgr.
const struct sockaddr * convertSockAddr(const SAType *sa)
Defines the logger used by the top-level component of kea-lfc.
Holds information about socket.