What is Netlink Socket Kernel Module Programming-Linux Kernel Development Course Online

Netlink Socket Kernel Module Programming
Building the Kernel-Side Netlink Handler on Modern Linux (Kernel 6.x)
Course
Free Linux Kernel Programming
Level
Intermediate
Kernel Version
6.x (Modern)
Part
3 of 3

← Previous Lecture  |  Next Lecture →

We now complete the picture from this free Linux kernel programming course: the kernel module that receives the message our user space client sends, logs it, and sends a reply. This lecture uses the modern netlink_kernel_create() API as it exists on current 6.x kernels, along with the associated cleanup you need for a leak-free module.

Topics Covered
netlink_kernel_create() struct netlink_kernel_cfg nlmsg_unicast() Kernel Module Programming Linux Device Drivers

What You Will Learn

Registering a netlink kernel socket Writing a receive callback Extracting sender info from skb Replying with nlmsg_unicast() Cleanup in module exit Security considerations

Prerequisites

This lecture assumes you’ve completed the previous two lectures on netlink concepts and user space programming, and that you’re already comfortable writing a basic loadable kernel module with module_init()/module_exit().

Step 1: Register the Netlink Kernel Socket

On the kernel side, you don’t call socket() and bind() the way user space does. Instead, you call netlink_kernel_create() once, typically from your module’s init function, passing a struct netlink_kernel_cfg that describes your callback function. This registers your module as the kernel-side endpoint for the chosen protocol number.

#include <linux/module.h>
#include <linux/netlink.h>
#include <net/sock.h>

#define EP_NETLINK_PROTO 25

static struct sock *ep_nl_sock;

static void ep_nl_recv_msg(struct sk_buff *skb);

static struct netlink_kernel_cfg ep_nl_cfg = {
    .input = ep_nl_recv_msg,
};

static int __init ep_netlink_init(void)
{
    ep_nl_sock = netlink_kernel_create(&init_net, EP_NETLINK_PROTO, &ep_nl_cfg);
    if (!ep_nl_sock) {
        pr_err("ep_netlink: failed to create netlink socket\n");
        return -ENOMEM;
    }
    pr_info("ep_netlink: kernel netlink socket ready\n");
    return 0;
}

Step 2: Write the Receive Callback

Every time a user space process sends a message on this protocol, the kernel invokes your input callback with the raw struct sk_buff. You extract the nlmsghdr from it, read the sender’s port ID (so you know who to reply to), and pull out the payload.

static void ep_nl_recv_msg(struct sk_buff *skb)
{
    struct nlmsghdr *nlh;
    int sender_pid;
    struct sk_buff *reply_skb;
    const char *reply_text = "message received by kernel";
    int msg_size = strlen(reply_text) + 1;

    nlh = (struct nlmsghdr *)skb->data;
    pr_info("ep_netlink: received: %s\n", (char *)nlmsg_data(nlh));

    sender_pid = nlh->nlmsg_pid;

    reply_skb = nlmsg_new(msg_size, GFP_KERNEL);
    if (!reply_skb) {
        pr_err("ep_netlink: failed to allocate reply skb\n");
        return;
    }

    nlh = nlmsg_put(reply_skb, 0, 0, NLMSG_DONE, msg_size, 0);
    strcpy(nlmsg_data(nlh), reply_text);

    nlmsg_unicast(ep_nl_sock, reply_skb, sender_pid);
}
Kernel-Side Message Flow
1. Module init calls netlink_kernel_create()
2. User space sendmsg() triggers ep_nl_recv_msg()
3. Callback reads sender_pid from nlh->nlmsg_pid
4. nlmsg_unicast() sends the reply back

Step 3: Clean Up on Module Exit

Forgetting to release the netlink kernel socket is one of the most common causes of a kernel module that can’t be safely unloaded and reloaded. Always call netlink_kernel_release() in your exit function.

static void __exit ep_netlink_exit(void)
{
    netlink_kernel_release(ep_nl_sock);
    pr_info("ep_netlink: kernel netlink socket released\n");
}

module_init(ep_netlink_init);
module_exit(ep_netlink_exit);
MODULE_LICENSE("GPL");

Security Considerations

  • Never trust the payload length blindly — validate nlh->nlmsg_len before reading past it to avoid out-of-bounds access.
  • Consider checking the sender’s credentials (available via NETLINK_CB(skb)) if your protocol should be restricted to privileged callers.
  • Avoid echoing untrusted input directly into printk/pr_info format strings — always use a format specifier like %s.

Performance Considerations

Netlink messages are queued, and under sustained high-frequency traffic the receive queue can fill up, causing messages to be dropped rather than blocking the sender. If your driver needs guaranteed delivery of every event, design an application-level acknowledgment scheme on top of netlink rather than assuming delivery.

Common Mistakes and Troubleshooting

Symptom Likely Cause
Module fails to load, insmod errors Protocol number already registered by another module
User space never gets a reply nlmsg_unicast() called with the wrong sender_pid
Kernel warning on module unload Missing netlink_kernel_release() call

Key Takeaways

A kernel-side netlink handler is registered once via netlink_kernel_create() with a callback that fires on every incoming message. Inside that callback you read the sender’s port ID from the message header and reply with nlmsg_unicast(). Always release the socket in your exit function to keep the module safely reloadable.

Frequently Asked Questions

Q1. Does netlink_kernel_create() block waiting for messages?
No, it just registers the callback; message delivery happens asynchronously whenever user space sends data.

Q2. Can multiple user space processes talk to the same kernel netlink family?
Yes, each with its own unique port ID, and the kernel can reply to each individually using nlmsg_unicast().

Q3. What’s the difference between nlmsg_unicast() and broadcasting?
nlmsg_unicast() replies to a single specific port ID, while broadcast delivery sends to every process subscribed to a multicast group.

Q4. Do I need generic netlink instead of this raw approach for a real driver?
For new, general-purpose drivers, generic netlink is usually recommended, but understanding the raw approach first makes the generic netlink API far easier to follow.

Q5. Why does my callback run in a strange context?
Netlink receive callbacks can run in a context where sleeping isn’t always safe depending on configuration — avoid blocking calls inside the callback unless you’ve confirmed it’s safe for your setup.

You’ve Completed the Netlink Sockets Mini-Series!

Continue exploring the free Linux kernel programming course and free Linux device drivers course for more hands-on kernel module tutorials.

Next Lecture → Back to Course Index

← Previous Lecture  |  Next Lecture →

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *