thom311 / libnl

Netlink Library Suite
GNU Lesser General Public License v2.1
423 stars 311 forks source link

not getting RTM_DELLINK netlink event #280

Open VenkateswaranJ opened 3 years ago

VenkateswaranJ commented 3 years ago

I have a small test code that checks for eth interface up/down events from the RTNLGRP_LINKmulticast 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(test 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)
chengyechun commented 2 years ago

excuse me, unplug and replug the network cable is same as eth interface up/down?

KanjiMonster commented 1 year ago

The RTM_NEWLINK is telling you that the link was updated (there is no explicit "updated" message type), and it lost its carrier (or gained it). You will see this is you check the contents of the IFLA_CARRIER field in the messages.

RTM_DELLINK will only be sent out if a network interface is removed completely, e.g. when deleting a vlan interface via ip link del ....