Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Netlink Communication between Kernel and User space
Z. QIU
Z. QIU

Posted on

     

Netlink Communication between Kernel and User space

Last year, I have usedNetlink in my development work for collecting some events from kernel space. I present in this post some basic practice I have done when I learnt to program withNetlink.

Introduction

Netlink is a Linux kernel interface used for** inter-process communication (IPC)** between both the kernel and userspace processes, and between different userspace processes, in a way similar to theUnix domain sockets. Similarly to the Unix domain sockets, and unlikeINET sockets, Netlink communication cannot traverse host boundaries.Netlink provides a standard socket-based interface for userspace processes, and a kernel-side API for internal use by kernel modules. Originally,Netlink used theAF_NETLINK socket family.Netlink is designed to be a more flexible successor toioctl; RFC 3549 describes the protocol in detail.

My practice

Kernel module

Below is the content of my source file "netlink_kernel.c" which yields a kernel module. There is macroMY_NETLINK 30 which defines my customized netlink protocol. One can also choose available protocols such likeNETLINK_ROUTE orNETLINK_INET_DIAG. All available protocols can be seen inthis page. Functionnetlink_kernel_create() creates a netlink socket for user space application to communicate with. More information about netlink programming can foundhere.

netlink_kernel.c

#include<linux/module.h>#include<net/sock.h>#include<linux/netlink.h>#include<linux/skbuff.h>/*  refer to https://elixir.bootlin.com/linux/v5.15.13/source/include/linux/netlink.h*/#define MY_NETLINK 30  // cannot be larger than 31, otherwise we shall get "insmod: ERROR: could not insert module netlink_kernel.ko: No child processes"structsock*nl_sk=NULL;staticvoidmyNetLink_recv_msg(structsk_buff*skb){structnlmsghdr*nlhead;structsk_buff*skb_out;intpid,res,msg_size;char*msg="Hello msg from kernel";printk(KERN_INFO"Entering: %s\n",__FUNCTION__);msg_size=strlen(msg);nlhead=(structnlmsghdr*)skb->data;//nlhead message comes from skb's data... (sk_buff: unsigned char *data)printk(KERN_INFO"MyNetlink has received: %s\n",(char*)nlmsg_data(nlhead));pid=nlhead->nlmsg_pid;// Sending process port ID, will send new message back to the 'user space sender'skb_out=nlmsg_new(msg_size,0);//nlmsg_new - Allocate a new netlink message: skb_outif(!skb_out){printk(KERN_ERR"Failed to allocate new skb\n");return;}nlhead=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);// Add a new netlink message to an skbNETLINK_CB(skb_out).dst_group=0;strncpy(nlmsg_data(nlhead),msg,msg_size);//char *strncpy(char *dest, const char *src, size_t count)res=nlmsg_unicast(nl_sk,skb_out,pid);if(res<0)printk(KERN_INFO"Error while sending back to user\n");}staticint__initmyNetLink_init(void){structnetlink_kernel_cfgcfg={.input=myNetLink_recv_msg,};/*netlink_kernel_create() returns a pointer, should be checked with == NULL */nl_sk=netlink_kernel_create(&init_net,MY_NETLINK,&cfg);printk("Entering: %s, protocol family = %d\n",__FUNCTION__,MY_NETLINK);if(!nl_sk){printk(KERN_ALERT"Error creating socket.\n");return-10;}printk("MyNetLink Init OK!\n");return0;}staticvoid__exitmyNetLink_exit(void){printk(KERN_INFO"exiting myNetLink module\n");netlink_kernel_release(nl_sk);}module_init(myNetLink_init);module_exit(myNetLink_exit);MODULE_LICENSE("GPL");
Enter fullscreen modeExit fullscreen mode

User space application

Below are the content of my file "netlink_client.c". This program shall open a netlink socket with the same protocol and allow user to send/receive msg to/from kernel module in previous section.

"netlink_client.c"

#include<sys/types.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>#include<sys/socket.h>#include<sys/types.h>#include<string.h>#include<asm/types.h>#include<linux/netlink.h>#include<linux/socket.h>#include<errno.h>#define NETLINK_USER 30 // same customized protocol as in my kernel module#define MAX_PAYLOAD 1024 // maximum payload sizestructsockaddr_nlsrc_addr,dest_addr;structnlmsghdr*nlh=NULL;structnlmsghdr*nlh2=NULL;structmsghdrmsg,resp;// famous struct msghdr, it includes "struct iovec *   msg_iov;"structioveciov,iov2;intsock_fd;intmain(intargs,char*argv[]){//int socket(int domain, int type, int protocol);sock_fd=socket(PF_NETLINK,SOCK_RAW,NETLINK_USER);//NETLINK_KOBJECT_UEVENTif(sock_fd<0)return-1;memset(&src_addr,0,sizeof(src_addr));src_addr.nl_family=AF_NETLINK;src_addr.nl_pid=getpid();/* self pid *///int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);if(bind(sock_fd,(structsockaddr*)&src_addr,sizeof(src_addr))){perror("bind() error\n");close(sock_fd);return-1;}memset(&dest_addr,0,sizeof(dest_addr));dest_addr.nl_family=AF_NETLINK;dest_addr.nl_pid=0;/* For Linux Kernel */dest_addr.nl_groups=0;/* unicast *///nlh: contains "Hello" msgnlh=(structnlmsghdr*)malloc(NLMSG_SPACE(MAX_PAYLOAD));memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));nlh->nlmsg_len=NLMSG_SPACE(MAX_PAYLOAD);nlh->nlmsg_pid=getpid();//self pidnlh->nlmsg_flags=0;//nlh2: contains received msgnlh2=(structnlmsghdr*)malloc(NLMSG_SPACE(MAX_PAYLOAD));memset(nlh2,0,NLMSG_SPACE(MAX_PAYLOAD));nlh2->nlmsg_len=NLMSG_SPACE(MAX_PAYLOAD);nlh2->nlmsg_pid=getpid();//self pidnlh2->nlmsg_flags=0;strcpy(NLMSG_DATA(nlh),"Hello this is a msg from userspace");//put "Hello" msg into nlhiov.iov_base=(void*)nlh;//iov -> nlhiov.iov_len=nlh->nlmsg_len;msg.msg_name=(void*)&dest_addr;//msg_name is Socket name: destmsg.msg_namelen=sizeof(dest_addr);msg.msg_iov=&iov;//msg -> iovmsg.msg_iovlen=1;iov2.iov_base=(void*)nlh2;//iov -> nlh2iov2.iov_len=nlh2->nlmsg_len;resp.msg_name=(void*)&dest_addr;//msg_name is Socket name: destresp.msg_namelen=sizeof(dest_addr);resp.msg_iov=&iov2;//resp -> iovresp.msg_iovlen=1;printf("Sending message to kernel\n");intret=sendmsg(sock_fd,&msg,0);printf("send ret: %d\n",ret);printf("Waiting for message from kernel\n");/* Read message from kernel */recvmsg(sock_fd,&resp,0);//msg is also receiver for readprintf("Received message payload: %s\n",(char*)NLMSG_DATA(nlh2));charusermsg[MAX_PAYLOAD];while(1){printf("Input your msg for sending to kernel: ");scanf("%s",usermsg);strcpy(NLMSG_DATA(nlh),usermsg);//put "Hello" msg into nlhprintf("Sending message\" %s\" to kernel\n",usermsg);ret=sendmsg(sock_fd,&msg,0);printf("send ret: %d\n",ret);printf("Waiting for message from kernel\n");/* Read message from kernel */recvmsg(sock_fd,&resp,0);//msg is also receiver for readprintf("Received message payload: %s\n",(char*)NLMSG_DATA(nlh2));}close(sock_fd);return0;}
Enter fullscreen modeExit fullscreen mode

Makefile

Create a Makefile with the following content which will enable us to easily compile the source files.

Makefile

obj-m += netlink_kernel.o#generate the pathCURRENT_PATH:=$(shellpwd)#the current kernel version numberLINUX_KERNEL:=$(shelluname-r)#the absolute pathLINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)#complie object#   extension of "make modules" cmd with -C option and "M=dir" configuration#   this cmd will switch working directory to the given path followed by the -C option#   and will search specified source files from the given path configured by "M="#   and compile them to generate ko filesall:    @echo$(LINUX_KERNEL_PATH)    make-C$(LINUX_KERNEL_PATH)M=$(CURRENT_PATH) modulesclient:    gcc netlink_client.c-o netlink_client-g#cleanclean:    make-C$(LINUX_KERNEL_PATH)M=$(CURRENT_PATH) cleanrmnetlink_client
Enter fullscreen modeExit fullscreen mode

Test the communication

Make sure that files "netlink_kernel.c", "netlink_client.c" and "Makefile" are in the same directory. In a Linux terminal window,cd into this directory and start the compilation:

make make client
Enter fullscreen modeExit fullscreen mode

Normally kernel module file "netlink_kernel.ko" and user application file "netlink_client" will be generated.

Load the generated kernel module "netlink_kernel.ko" to linux kernel:

sudoinsmod netlink_kernel.ko
Enter fullscreen modeExit fullscreen mode

Execute in a new terminal the following cmd to monitor the kernel messages:

dmesg -Hw
Enter fullscreen modeExit fullscreen mode

Now start the user application to start the communication:

./netlink_client
Enter fullscreen modeExit fullscreen mode

Below is the screenshot of my test:
Image description

Top comments(1)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
trn_ngclong profile image
Trần Ngọc Long
Passion
  • Joined

Very nice

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Location
    Paris, France
  • Work
    Software Engineer, Architect, Robotics Engineer at Suwen AI, GE Healthcare
  • Joined

Trending onDEV CommunityHot

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp