I have a small test code that checks for eth interface up/down events from the RTNLGRP_LINK
multicast group, but unfortunately, I'm always getting the RTM_NEWLINK
event even when I unplug and replug the network cable. I expect RTM_DELLINK
when I unplug the cable and RTM_NEWLINK
when the cable is connected. I'm using libnl-3.4.0 library.
can anyone point out what I'm doing wrong?
extern "C"
{
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <arpa/inet.h>
}
#include <iostream>
static int parseLink(struct nlmsghdr *hdr)
{
struct ifinfomsg *iface = (struct ifinfomsg *)nlmsg_data(hdr);
struct nlattr *attrs[IFLA_MAX + 1];
if (nlmsg_parse(hdr, sizeof(struct ifinfomsg), attrs, IFLA_MAX, nullptr) < 0)
{
std::cerr << "problem parsing Netlink response" << std::endl;
return -1;
}
if (attrs[IFLA_IFNAME] != nullptr)
{
if (hdr->nlmsg_type == RTM_NEWLINK)
{
std::cout << "Interface " << (char *)nla_data(attrs[IFLA_IFNAME]) << " added" << std::endl;
}
else if (hdr->nlmsg_type == RTM_DELLINK)
{
std::cout << "Interface " << (char *)nla_data(attrs[IFLA_IFNAME]) << " deleted" << std::endl;
}
}
return 0;
}
static int receiveNewMsg(struct nl_msg *msg, void *arg)
{
struct nlmsghdr *nlh = nlmsg_hdr(msg);
int len = nlh->nlmsg_len;
while (nlmsg_ok(nlh, len))
{
if (nlh->nlmsg_type != RTM_NEWLINK && nlh->nlmsg_type != RTM_DELLINK)
{
if (nlh->nlmsg_type == NLMSG_DONE)
{
std::cout << "message complete" << std::endl;
}
nlh = nlmsg_next(nlh, &len);
continue;
}
if ((nlh->nlmsg_type == RTM_DELLINK) || (nlh->nlmsg_type == RTM_NEWLINK))
{
parseLink(nlh);
}
nlh = nlmsg_next(nlh, &len);
}
return 0;
}
int main(int argc, char const *argv[])
{
struct nl_sock *sk;
/* Allocate a new socket */
sk = nl_socket_alloc();
/*
* Notifications do not use sequence numbers, disable sequence number checking.
*/
nl_socket_disable_seq_check(sk);
/*
* Define a callback function, which will be called for each notification received
*/
nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, receiveNewMsg, nullptr);
nl_socket_modify_cb(sk, NL_CB_FINISH, NL_CB_CUSTOM, receiveNewMsg, nullptr);
/* Connect to routing netlink protocol */
nl_connect(sk, NETLINK_ROUTE);
/* Subscribe to link notifications group */
nl_socket_add_memberships(sk, RTNLGRP_LINK);
/*
* Start receiving messages. The function nl_recvmsgs_default() will block
* until one or more netlink messages (notification) are received which
* will be passed on to my_func().
*/
while (1)
nl_recvmsgs_default(sk);
return 0;
}
CMakeLists.txt to compile the above code:
cmake_minimum_required(VERSION 3.10)
project(mptcpd VERSION 0.1 LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
include_directories(/usr/include/libnl3/)
file(GLOB SOURCES
*.h
*.cpp
)
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} libnl-3.so)
Update: I thought it's something to do with the libnl library so I tried an example without libnl library but the thing is the same.
Here is the example I tried: http://olegkutkov.me/2018/02/14/monitoring-linux-networking-state-using-netlink/