Netlink

Netlink is a message-based communication mechanism used in the Linux kernel between the kernel and user-space processes. It is implemented through a socket interface and a custom protocol family, and can be used to deliver various types of kernel messages, including network device status, routing table updates, firewall rule changes, system resource usage, and so on. SONiC's *sync service makes extensive use of Netlink's mechanism to listen for changes to network devices in the system, synchronize the latest state to Redis, and notify other services of the corresponding changes.

Netlink的实现主要在这几个文件中:common/netmsg.*common/netlink.*common/netdispatcher.*,具体类图如下:

Among them:

  • Netlink:封装了Netlink的套接字接口,提供了Netlink消息的接口和接收消息的回调。
  • NetDispatcher:它是一个单例,提供了Handler注册的接口。当Netlink类接收到原始的消息后,就会调用NetDispatcher将其解析成nl_onject,并根据消息的类型调用相应的Handler。
  • NetMsg:Netlink消息Handler的基类,仅提供了onMsg的接口,其中没有实现。

As an example, when portsyncd starts, it will create a Netlink object to listen for Link-related state changes and will implement the NetMsg interface to handle Link-related messages. The concrete implementation is as follows:

// File: sonic-swss - portsyncd/portsyncd.cpp
int main(int argc, char **argv)
{
    // ...

    // Create Netlink object to listen to link messages
    NetLink netlink;
    netlink.registerGroup(RTNLGRP_LINK);

    // Here SONiC request a fulldump of current state, so that it can get the current state of all links
    netlink.dumpRequest(RTM_GETLINK);      
    cout << "Listen to link messages..." << endl;
    // ...

    // Register handler for link messages
    LinkSync sync(&appl_db, &state_db);
    NetDispatcher::getInstance().registerMessageHandler(RTM_NEWLINK, &sync);
    NetDispatcher::getInstance().registerMessageHandler(RTM_DELLINK, &sync);

    // ...
}

The above LinkSync, which is an implementation of NetMsg, implements the onMsg interface to handle Link-related messages::

// File: sonic-swss - portsyncd/linksync.h
class LinkSync : public NetMsg
{
public:
    LinkSync(DBConnector *appl_db, DBConnector *state_db);

    // NetMsg interface
    virtual void onMsg(int nlmsg_type, struct nl_object *obj);

    // ...
};

// File: sonic-swss - portsyncd/linksync.cpp
void LinkSync::onMsg(int nlmsg_type, struct nl_object *obj)
{
    // ...

    // Write link state to Redis DB
    FieldValueTuple fv("oper_status", oper ? "up" : "down");
    vector<FieldValueTuple> fvs;
    fvs.push_back(fv);
    m_stateMgmtPortTable.set(key, fvs);
    // ...
}

参考资料

  1. Github repo: sonic-swss-common