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.