5

Say that i have registered a generic netlink interface using genl_register_family_with_ops with multiple callbacks.

I don't see any warnings about it and I assume the callbacks are serially called but there is no information about how the callbacks are called neither.

Is it possible that multiple callbacks are called concurrently on the same generic netlink interface I have registered? Do I need any synchronization between the callbacks?

To make the question simpler:

Can a single netlink callback be preempted or concurrently run in two cores?

Etherealone
  • 3,488
  • 2
  • 37
  • 56
  • Call backs are called when an event occurs,. If another event happens before the callback ends, then it will get an overlapping call. – stark Sep 11 '15 at 14:13
  • @stark I'm more specifically asking if I can get two events on the same netlink family registration which can make the callbacks overlap. There is only one registration with multiple callbacks. Netlink callbacks will be modifying the same structures and the structures will only be modified/accessed by netlink callbacks. – Etherealone Sep 11 '15 at 14:48
  • 1
    @Etherealone I suspect the answer is that this is configurable, but off by default. In my copy of kernel 3.11's sources, the `struct genl_family` contains a `bool parallel_ops`. In `linux-3.11.10-21/net/netlink/genetlink.c:674` or nearabouts, in `genl_rcv_msg()`, if that flag is not set, then a global mutex is locked, the request is processed, and the global mutex unlocked. If it is set then this locking doesn't happen. – Iwillnotexist Idonotexist Sep 11 '15 at 15:39
  • @IwillnotexistIdonotexist I think you are right. I missed it but it actually refers to synchronization on operation callbacks in 4.2 `genetlink.h`, too. That should cover both multiple callbacks and single callback concurrency. Implementation you are referring seems to be proving that. You should make that an answer. – Etherealone Sep 11 '15 at 16:10

1 Answers1

2

Answer assumes Linux kernel version 3.11 or 4.2, probably valid for many others. Answer current as of September 2015.

Whether callbacks may be concurrent or not is a configurable property of the struct genl_family at registration time, but if not explicitly specified, is probably defaulted to off. This is due to 1) The presence of a bool parallel_ops member in struct genl_family, and 2) Uninitialized members of a static-duration struct being defaulted to 0 in C.

On reception of a Netlink message, eventually the function genl_rcv_msg() is called, which determines the message's GeNetlink family and conditions on parallel_ops to decide whether or not to lock down the global genl_mutex.

static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
        struct genl_family *family;
        int err;

        family = genl_family_find_byid(nlh->nlmsg_type);
        if (family == NULL)
                return -ENOENT;

        if (!family->parallel_ops)
                genl_lock();

        err = genl_family_rcv_msg(family, skb, nlh);

        if (!family->parallel_ops)
                genl_unlock();

        return err;
}

Once genl_family_rcv_msg() is invoked (protected or unprotected by the mutex), the actual callback is invoked here.

Iwillnotexist Idonotexist
  • 13,297
  • 4
  • 43
  • 66