Netlink notifier chain

At Collabora we are working on improving the D-Bus IPC system. We are trying different approaches and one of them is implementing the D-Bus routing logic and match rules handling as a Generic Netlink service. Rodrigo wrote a great blog entry on the design of this Netlink solution.

A problem we found is that AF_NETLINK is not connection oriented. Applications don’t establish a connection before transmitting, they just open a socket and start sending messages. So, if an application close its socket, the other peers won’t notice. This also applies to the kernel code since in Generic Netlink, the in kernel service is just another user of the Netlink channel.

The problem is that D-bus is connection oriented, we have to keep track of each connection to the bus and remove it when the socket associate with the connection is closed.

Fortunately, the kernel has a mechanism known as notifier chains that allows kernel code to listen for certain events by registering to a specific notifier chain.

Netlink defines a notifier netlink_chain to notify when a socket is released (NETLINK_URELEASE event). So, we can use that information to remove the D-Bus connection associate with a socket when it is released.

The notifier API is very simple, we only have to define a notifier_block data structure and assign a function handler to the notifier_call function pointer. Once the notifier_block data structure is registered, the notifier_call function handler is called every time the events occurs.

I knew about notifier chains before but haven’t used until today so I thought it was something interesting to share. Here is a small example of how we can use the Netlink notifier chain:

static int dbus_netlink_notify(struct notifier_block *nb, unsigned long state,
                               void *_notify)
{
        struct netlink_notify *notify = _notify;

        if (state == NETLINK_URELEASE && notify->protocol == NETLINK_GENERIC)
                dbus_bus_del_connection(notify->pid);

        return NOTIFY_DONE;
}

static struct notifier_block dbus_netlink_notifier = {
	.notifier_call = dbus_netlink_notify,
};

static int __init dbus_init(void)
{
	int rc;

	rc = genl_register_family_with_ops(&dbus_family, dbus_ops,
					   ARRAY_SIZE(dbus_ops));
	if (rc)
                return rc;

	rc = netlink_register_notifier(&dbus_netlink_notifier);
	if (rc) {
                genl_unregister_family(&dbus_family);
                return rc;
	}

	return 0;
}

4 thoughts on “Netlink notifier chain

  1. They are defined above. I didn’t show all the Netlink code of the Generic Netlink dbus family for the sake of simplicity, only the code relevant to the notifier chain.

    This is how dbus_family (the Generic Netlink family for dbus) and dbus_ops (the Generic Netlink operations) are defined:

    
    static struct genl_family dbus_family = {
    	.id = GENL_ID_GENERATE,
    	.hdrsize = 0,
    	.name = "dbus",
    	.version = 1,
    	.maxattr = DBUS_ATTR_MAX,
    };
    
    static struct genl_ops dbus_ops[] = {
    	{
    		.cmd = DBUS_CMD_ADDBUS,
    		.policy = dbus_policy,
    		.doit = dbus_add_bus,
    	},
    	{
    		.cmd = DBUS_CMD_DELBUS,
    		.policy = dbus_policy,
    		.doit = dbus_del_bus,
    	},
    	{
    		.cmd = DBUS_CMD_CONBUS,
    		.policy = dbus_policy,
    		.doit = dbus_con_bus,
    	},
    	{
    		.cmd = DBUS_CMD_DISBUS,
    		.policy = dbus_policy,
    		.doit = dbus_dis_bus,
    	},
    };
    
    
    • When I wrote that post I was using 3.4 IIRC but it shouldn’t matter since the mechanism have not changed since (the API may had changed though since the kernel doesn’t have a stable API – see Documentation/stable_api_nonsense.txt)

Leave a reply to Javier Martinez Canillas Cancel reply