Linux Kernel Learning Notes 9: NetLink of communication between kernel and user layer

Source: Internet
Author: User
Tags goto sendmsg socket error strlen

(This chapter is based on: linux-4.4.0-37)

There are many ways to communicate between the kernel and user space, NetLink is one of them, and the others are/proc, IOCTL, sockopt, shared memory, and so on. NetLink is characterized by asynchronous Full-duplex.


NetLink uses 32-bit port addressing, called PID (not related to the process number), where the kernel's PID address is 0. The main characteristics of NetLink are as follows:

1 supports Full-duplex, asynchronous communication (of course sync also supports)

2 User space can use the standard BSD socket interface (but NetLink does not mask the construction and parsing process of the Protocol package, recommend the use of LIBNL, etc. third third-party)

3 use a dedicated kernel API interface in kernel space

4 support for multicasting (hence support for "bus" communication, which enables message subscriptions)

5 at the kernel end can be used for process context and interrupt context

Basic data structure


struct MSGHDR {
    void         *msg_name;       /* Optional Address * *
    socklen_t     Msg_namelen;    /* Size of Address *
    /struct Iovec *msg_iov;        /* Scatter/gather Array
    *        /size_t Msg_iovlen;     * * Elements in Msg_iov
    /void         *msg_control;    /* Ancillary data, below * *
    size_t        msg_controllen;/* Ancillary Data buffer len * *           /int msg_flags;      * FLAGS (UNUSED) */
};

struct SOCKADDR_NL
{
    sa_family_t nl_family;/* This field is always af_netlink
    /unsigned short nl_pad;/* not currently used, fill to 0* /
    __u32 nl_pid/* Process PID/
    __u32 nl_groups;/* Multicast Groups Mask * *
;


struct SOCKADDR_NL is the NetLink mailing address, which is the same as the sockaddr_in function of our usual socket programming. The PID represents the communication port, and the groups represents the group, note that this is the mask that you want to add a multicast group number to, that is, support up to 32 groups.
struct NLMSGHDR
{
    __u32 nlmsg_len;/* Length of message including header/__u16
    nlmsg_type;/* Message Conte NT/
    __u16 nlmsg_flags/* Additional flags/
    __u32 NLMSG_SEQ/* Sequence number
    /__u32 nlmsg_pid;/* Sen Ding process PID *
/};
The data area of the NetLink packet is composed of the message header and the message body, struct NLMSGHDR is the message header, and the message body is connected to the message header.


Kernel layer Operations

Create a socket

Static inline struct sock *
netlink_kernel_create (struct net *net, int unit, struct netlink_kernel_cfg);
NET: General Direct fill &init_net

Unit: protocol type, customizable, such as #define NETLINK_TEST 25

CFG: Configuration structure, type as follows:

/* Optional netlink Kernel configuration parameters
/struct netlink_kernel_cfg {unsigned
	int	groups;
	unsigned int	flags;
	void		(*input) (struct sk_buff *skb);
	struct mutex	*cb_mutex;
	int		(*bind) (struct net *net, int group);
	void		(*unbind) (struct net *net, int group);
	BOOL		(*compare) (struct net *net, struct sock *sk);

Groups: Group number;

Input: Receives a callback function, receives a SK_BUFF structure, the data contains a NLMSGHDR protocol header;

Return: Returns a sock structure that returns null to indicate that the creation failed;


Single-Broadcast delivery interface:

extern int Netlink_unicast (struct sock *ssk, struct Sk_buff *skb, __u32 portid, int nonblock);

(1) SSK: The socket returned for function netlink_kernel_create ().

(2) SKB: Holds the message, its data field points to the NetLink message structure to send, while the SKB control block holds the address information of the message, and the macro NETLINK_CB (SKB) is used to conveniently set the control block.

(3) Portid:pid port.

(4) Nonblock: Indicates whether the function is non-blocking, and if 1, the function returns immediately when no cache is available, and if 0, the function can use timed sleep without receiving caching.

Multi-Broadcast Delivery interface:

extern int Netlink_broadcast (struct sock *ssk, struct Sk_buff *skb, __u32 Portid,
			     __u32 Group, gfp_t allocation);
Group: A multicast group that receives messages, each of which represents a multicast group, so if sent to more than one multicast group;
Allocation: The memory allocation type, typically used for gfp_atomic or gfp_kernel,gfp_atomic in the context of the atom (that is, not sleep), and Gfp_kernel for the non-atomic context.


Release socket

extern void Netlink_kernel_release (struct sock *sk);


User Layer Actions

Common operations for NLMSGHDR structures:

Nlmsg_space (len): Adds Len to the length of the NLMSGHDR head and aligns to 4 bytes;

Nlmsg_data (NLH): Return to the first address of the data area;


Create Socke

int netlink_create_socket (void)
{
        //create a socket return
        socket (Af_netlink, Sock_raw, netlink_test);


Bind

int netlink_bind (int sock_fd)
{
        struct sockaddr_nl addr;

        memset (&addr, 0, sizeof (struct sockaddr_nl));
        addr.nl_family = Af_netlink;
        Addr.nl_pid = Test_pid;
        addr.nl_groups = 0;

        Return bind (SOCK_FD, (struct sockaddr *) &addr, sizeof (struct sockaddr_nl));


Send receive:

Send receive data using SENDMSG, recvmsg

ssize_t sendmsg (int sockfd, const struct MSGHDR *msg, int flags);
ssize_t recvmsg (int sockfd, struct MSGHDR *msg, int flags);


Send receive data using SendTo, Recvfrom

ssize_t sendto (int sockfd, const void *buf, size_t len, int flags,
                      const struct, sockaddr *dest_addr, socklen_t Addrlen );
ssize_t recvfrom (int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);


Example:

Description: The user layer PID is set to 100, the application layer sends a message to the kernel, the kernel replies the same information;

Kernel layer:

#include <linux/init.h> #include <linux/module.h> #include <linux/stat.h> #include <linux/kdev_ t.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/cdev.h> #include <asm/
uaccess.h> #include <net/netlink.h> #include <net/sock.h> #define NETLINK_TEST () static dev_t devid;
static struct Class *cls = NULL;

struct sock *nl_sk = NULL;
        static void Hello_cleanup (void) {netlink_kernel_release (NL_SK);
        Device_destroy (CLS, devid);
        Class_destroy (CLS);
Unregister_chrdev_region (Devid, 1);
        static void Netlink_send (int pid, uint8_t *message, int len) {struct Sk_buff *skb_1;

        struct NLMSGHDR *nlh;
        if (!message | |!nl_sk) {return;
        } skb_1 = Alloc_skb (Nlmsg_space (len), Gfp_kernel);
        if (!skb_1) {PRINTK (kern_err "ALLOC_SKB error!\n");
        } NLH = Nlmsg_put (skb_1, 0, 0, 0, len, 0); NetlinK_CB (skb_1). Portid = 0;
        NETLINK_CB (skb_1). Dst_group = 0;
        memcpy (Nlmsg_data (NLH), message, Len);
Netlink_unicast (Nl_sk, skb_1, PID, msg_dontwait);
        } static void Netlink_input (struct sk_buff *__skb) {struct sk_buff;
        Char str[100];

        struct NLMSGHDR *nlh;
        if (!__SKB) {return;
        } SKB = Skb_get (__SKB);
        if (Skb->len < Nlmsg_space (0)) {return;
        } NLH = Nlmsg_hdr (SKB);
        memset (str, 0, sizeof (str));
        memcpy (str, nlmsg_data (NLH), sizeof (str));
        PRINTK (kern_info "Receive Message" (pid:%d):%s\n ", Nlh->nlmsg_pid, str);
        PRINTK (kern_info "space:%d\n", Nlmsg_space (0));
        PRINTK (kern_info "size:%d\n", Nlh->nlmsg_len);

        Netlink_send (Nlh->nlmsg_pid, Nlmsg_data (NLH), Nlh->nlmsg_len-nlmsg_space (0));
Return
        static __init int Netlink_init (void) {int result; struct Netlink_kernel_cfg nkc

        PRINTK (kern_warning "NetLink init start!\n"); Dynamic Registration Device number if (result = Alloc_chrdev_region (&devid, 0, 1, "Stone-alloc-dev"))!= 0) {PRINTK (
                kern_warning "Register Dev ID error:%d\n", result);
        Goto err;
        else {PRINTK (kern_warning "Register dev ID success!\n");
        ///Dynamically create device Node CLS = class_create (This_module, "Stone-class");
                if (Is_err (CLS)) {PRINTK (kern_warning "Create Class error!\n");
        Goto err; } if (CLS, NULL, Devid, "", "hello%d", 0) = NULL) {PRINTK (kern_warning "Create Devi") (Device_create)
                Ce error!\n ");
        Goto err;
        }//Initialize NetLink nkc.groups = 0;
        nkc.flags = 0;
        Nkc.input = Netlink_input;
        Nkc.cb_mutex = NULL;
        Nkc.bind = NULL;
        Nkc.unbind = NULL;
        Nkc.compare = NULL; Nl_sk = Netlink_kernel_create (&init_net, NETlink_test, &AMP;NKC);
                if (!nl_sk) {PRINTK (kern_err "[NetLink] Create NetLink socket error!\n");
        Goto err;
        } PRINTK (Kern_alert "NetLink init success!\n");
return 0;
        Err:hello_cleanup ();
return-1;
        static __exit void Netlink_exit (void) {hello_cleanup ();
PRINTK (kern_warning "NetLink exit!\n");
} module_init (Netlink_init);

Module_exit (Netlink_exit);
Module_license ("GPL"); Module_author ("Stone");

Application Layer 1:

#include <sys/stat.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include < sys/socket.h> #include <string.h> #include <asm/types.h> #include <linux/netlink.h> #include <        linux/socket.h> #include <errno.h> #define NETLINK_TEST #define MAX_PAYLOAD (1024) #define Test_pid (m) int netlink_create_socket (void) {//create a socket return socket (Af_netlink, Sock_raw, Netl
Ink_test);

        int netlink_bind (int sock_fd) {struct SOCKADDR_NL addr;
        memset (&addr, 0, sizeof (struct sockaddr_nl));
        addr.nl_family = Af_netlink;
        Addr.nl_pid = Test_pid;

        addr.nl_groups = 0;
Return bind (SOCK_FD, (struct sockaddr *) &addr, sizeof (struct sockaddr_nl)); int netlink_send_message (int sock_fd, const unsigned char *message, int len, UN signed int PID, unsigned int group) {struct NLMSGHDR *nlh = NULL;
        struct SOCKADDR_NL dest_addr;
        struct Iovec Iov;

        struct MSGHDR msg;
        if (!message) {return-1;
        }//create message Nlh = (struct NLMSGHDR *) malloc (Nlmsg_space (len));
                if (!NLH) {perror ("malloc");
        Return-2;
        } Nlh->nlmsg_len = Nlmsg_space (len);
        Nlh->nlmsg_pid = Test_pid;
        nlh->nlmsg_flags = 0;

        memcpy (Nlmsg_data (NLH), message, Len);
        Iov.iov_base = (void *) NLH;
        Iov.iov_len = nlh->nlmsg_len;
        memset (&dest_addr, 0, sizeof (struct sockaddr_nl));
        dest_addr.nl_family = Af_netlink;
        Dest_addr.nl_pid = pid;

        Dest_addr.nl_groups = Group;
        memset (&msg, 0, sizeof (struct MSGHDR));
        Msg.msg_name = (void *) &dest_addr;
        Msg.msg_namelen = sizeof (struct SOCKADDR_NL);
        Msg.msg_iov = &iov;

        Msg.msg_iovlen = 1; Send Message if (SENdmsg (SOCK_FD, &msg, 0) < 0) {printf ("Send error!\n");
                Free (NLH);
        return-3;
        Free (NLH);
return 0;
        int netlink_recv_message (int sock_fd, unsigned char *message, int *len) {struct NLMSGHDR *nlh = NULL;
        struct SOCKADDR_NL source_addr;
        struct Iovec Iov;

        struct MSGHDR msg;
        if (!message | |!len) {return-1;
        }//create message Nlh = (struct NLMSGHDR *) malloc (Nlmsg_space (max_payload));
                if (!NLH) {perror ("malloc");
        Return-2;
        } iov.iov_base = (void *) NLH;
        Iov.iov_len = Nlmsg_space (max_payload);
        memset (&source_addr, 0, sizeof (struct sockaddr_nl));
        memset (&msg, 0, sizeof (struct MSGHDR));
        Msg.msg_name = (void *) &source_addr;
        Msg.msg_namelen = sizeof (struct SOCKADDR_NL);
        Msg.msg_iov = &iov; Msg. Msg_iovlen = 1;
                if (Recvmsg (sock_fd, &msg, 0) < 0) {printf ("recvmsg error!\n");
        return-3;
        } *len = Nlh->nlmsg_len-nlmsg_space (0);

        memcpy (message, (unsigned char *) nlmsg_data (NLH), *len);
        Free (NLH);
return 0;
        int main (int argc, char **argv) {int sock_fd;
        Char Buf[max_payload];

        int Len;
                if (ARGC < 2) {printf ("Enter message!\n");
        Exit (Exit_failure);
        } SOCK_FD = Netlink_create_socket ();
                if (sock_fd = = 1) {printf ("Socket error!\n");
        return-1;
                } if (Netlink_bind (SOCK_FD) < 0) {perror ("bind");
                Close (SOCK_FD);
        Exit (Exit_failure);
        } netlink_send_message (SOCK_FD, argv[1], strlen (argv[1]) + 1, 0, 0); if (Netlink_recv_message (SOCK_FD, buf, &len) = 0) {priNTF ("recv:%s len:%d\n", buf, Len);
        Close (SOCK_FD);
return 0; }

The above example is about using Sendmsg, recvmsg. In the application layer we can also use SendTo, Recvfrom send receive data, operating mode and UDP communication is very similar to the difference is to be able to receive data successfully, we also need to bind to the use of bind () the address, but for UDP this is not necessary;


Application Layer 2:

#include <sys/stat.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include < sys/socket.h> #include <string.h> #include <asm/types.h> #include <linux/netlink.h> #include <        linux/socket.h> #include <errno.h> #define NETLINK_TEST #define MAX_PAYLOAD (1024) #define Test_pid (m) int netlink_create_socket (void) {//create a socket return socket (Af_netlink, Sock_raw, Netl
Ink_test);

        int netlink_bind (int sock_fd) {struct SOCKADDR_NL addr;
        memset (&addr, 0, sizeof (struct sockaddr_nl));
        addr.nl_family = Af_netlink;
        Addr.nl_pid = Test_pid;

        addr.nl_groups = 0;
Return bind (SOCK_FD, (struct sockaddr *) &addr, sizeof (struct sockaddr_nl)); int netlink_send_message (int sock_fd, const unsigned char *message, int len, UN signed int PID, unsigned int group) {struct NLMSGHDR *nlh = NULL;
        struct SOCKADDR_NL dest_addr;
        if (!message) {return-1;
        }//create message Nlh = (struct NLMSGHDR *) malloc (Nlmsg_space (len));
                if (!NLH) {perror ("malloc");
        Return-2;
        } Nlh->nlmsg_len = Nlmsg_space (len);
        Nlh->nlmsg_pid = Test_pid;
        nlh->nlmsg_flags = 0;

        memcpy (Nlmsg_data (NLH), message, Len);
        memset (&dest_addr, 0, sizeof (struct sockaddr_nl));
        dest_addr.nl_family = Af_netlink;
        Dest_addr.nl_pid = pid;

        Dest_addr.nl_groups = Group; Send Message if (SendTo (SOCK_FD, NLH, Nlh->nlmsg_len, 0, struct sockaddr *) &dest_addr, sizeof (struct SOC
                KADDR_NL))!= Nlh->nlmsg_len) {printf ("Send error!\n");
                Free (NLH);
        return-3;
        Free (NLH);
return 0; int netlink_recv_message (int sock_fd, unsigned char *message, int *leN) {struct NLMSGHDR *nlh = NULL;
        struct SOCKADDR_NL src_addr;

        socklen_t addrlen = sizeof (struct SOCKADDR_NL);
        if (!message | |!len) {return-1;
        }//create message Nlh = (struct NLMSGHDR *) malloc (Nlmsg_space (max_payload));
                if (!NLH) {perror ("malloc");
        Return-2;
        memset (&src_addr, 0, sizeof (struct sockaddr_nl)); if (Recvfrom (SOCK_FD, NLH, Nlmsg_space (Max_payload), 0, (struct sockaddr *) &src_addr, (socklen_t *) &addrlen)
                < 0) {printf ("recvmsg error!\n");
        return-3;
        } *len = Nlh->nlmsg_len-nlmsg_space (0);

        memcpy (message, (unsigned char *) nlmsg_data (NLH), *len);
        Free (NLH);
return 0;
        int main (int argc, char **argv) {int sock_fd;
        Char Buf[max_payload];

        int Len; if (ARGC < 2) {printf ("Enter message!\n");
        Exit (Exit_failure);
        } SOCK_FD = Netlink_create_socket ();
                if (sock_fd = = 1) {printf ("Socket error!\n");
        return-1;
                } if (Netlink_bind (SOCK_FD) < 0) {perror ("bind");
                Close (SOCK_FD);
        Exit (Exit_failure);
        } netlink_send_message (SOCK_FD, argv[1], strlen (argv[1]) + 1, 0, 0);
        if (Netlink_recv_message (SOCK_FD, buf, &len) = = 0) {printf ("recv:%s len:%d\n", buf, Len);
        Close (SOCK_FD);
return 0;
 }




Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.