Communication between user program and kernel under linux (netlink mechanism)

  • 2020-06-23 02:34:12
  • OfStack

Introduction to the

linux user programs communicate with the kernel 1 ioctl, proc file system, the remaining one is the Netlink socket. Here's a look at netlink.

Netlink is a very good way for bidirectional data transmission between the kernel and user applications. User mode applications can use the powerful functions provided by netlink using the standard socket API, and kernel mode requires the special kernel API to use netlink.

Netlink has the following advantages over system calls, ioctl, and /proc file systems:

1, in order to use netlink, users need only in include/linux/netlink. Add a new type of h netlink agreement can be defined, such as # define NETLINK_MYTEST 17 and then, the kernel and user mode application can immediately by socket API using the netlink protocol type for data exchange. But system calls need to add new system calls, ioctl needs to add devices or files, which requires a lot of code, and proc file systems need to add new files or directories under /proc, which will make /proc even more confusing.

2. netlink is one kind of asynchronous communication mechanism, the news of the passing between kernel and user mode application in socket buffer queue, socket send messages just keep the message in the receiver of the queue, but do not need to wait for the receiver receive messages, but the system call and ioctl is synchronous communication mechanism, if the data is too long, will affect scheduling granularity.

3. Using the kernel part of netlink can use module implementation, using netlink application and the kernel part of no compile-time dependencies, but the system call is to rely on, and the realization of the new system calls must be statically connected to the kernel, it cannot be achieved in the module using the application of the new system calls at compile time depends on the kernel.

4. netlink support multicast, the kernel module or application can you give a netlink message multicast group, belong to the group neilink any kernel module or application can receive the message, the kernel event notification to the user mode mechanism to use this feature, 1 the application of any interested in the kernel event will receive the subsystem of the kernel event, in the back of the article will introduce the use of this 1 mechanism.

5. The kernel can initiate the session using netlink, but the system call and ioctl can only be initiated by the user application.

6. netlink USES the standard socket API and is therefore easy to use, but system calls and ioctl require specialized training.

The main purpose of the following two sections of code is to communicate between the user program and the kernel using the netlink mechanism. The kernel will return "S know you!" when the user program executes./ netlink-ES75en [I am the parameter] or./ netlink-ES77en. And "I know you!" These two strings, and then output. Both the kernel and the user program are printed.

The kernel module

Makefile - ruler. dir


PWD := $(shell pwd) 
 
all: modules romfs 
 
modules: 
 $(MAKE) -C $(KDIR) M=$(PWD) modules 
 @echo $(OBJ) 
 
modules_install: 
 $(MAKE) -C $(KDIR) M=$(PWD) modules_install 
 
romfs: 
 cp -rf *.ko $(MODULES_BUILD_DIR) 
 
clean: 
 rm *.o *.ko *.mod.* Module.* modules.* 
 rm -rf $(MODULES_BUILD_DIR) 
 
obj-m := $(MOD_NAME).o 

2.Makefile


KERNEL_MODULES := netlink 
 
export MODULES_ROOT_DIR := $(shell pwd) 
export MODULES_BUILD_DIR := $(MODULES_ROOT_DIR)/build 
export KDIR := /lib/modules/$(shell uname -r)/build # This line is for the kernel directory under the system (ubuntu) 
 
all: init modules romfs 
 
init: 
 mkdir -p $(MODULES_BUILD_DIR) 
 
modules:$(patsubst %, _dir_%, $(KERNEL_MODULES)) 
 
$(patsubst %, _dir_%, $(KERNEL_MODULES)): 
 @echo 
 @echo Building $(patsubst _dir_%, %, $@) 
 $(MAKE) -C $(patsubst _dir_%, %, $@) all 
 
 
romfs: $(patsubst %, _romfs_%, $(KERNEL_MODULES)) 
$(patsubst %, _romfs_%, $(KERNEL_MODULES)): 
 $(MAKE) -C $(patsubst _romfs_%, %, $@) romfs 
 
 
clean: $(patsubst %, _clean_%, $(KERNEL_MODULES)) 
 $(RM) $(BUILD_DIR) 
$(patsubst %, _clean_%, $(KERNEL_MODULES)): 
 @echo 
 @echo Cleaning $(patsubst _dir_%, %, $@) 
 $(MAKE) -C $(patsubst _clean_%, %, $@) clean 
 
.PHONY: 

3. ./netlink/netlink.c


/* 
 * netlink.c 
 * 
 * Created on: 2014 *  Author: cr 
 */ 
 
#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/skbuff.h> 
#include <linux/ip.h> 
#include <linux/types.h> 
#include <linux/sched.h> 
#include <linux/netlink.h> 
#include <net/sock.h> 
#include "usrlink.h" 
 
MODULE_LICENSE("Dual BSD/GPL"); 
MODULE_AUTHOR("MDAXIA"); 
 
struct sock *netlink_fd; 
 
 
static void netlink_to_user(int dest, void *buf, int len) 
{ 
 struct nlmsghdr *nl; 
 struct sk_buff *skb; 
 int size; 
 
 size = NLMSG_SPACE(len); 
 skb = alloc_skb(size, GFP_ATOMIC); 
 if(!skb || !buf) 
 { 
  printk(KERN_ALERT "netlink_to_user skb of buf null!\n"); 
  return; 
 } 
 nl = nlmsg_put(skb, 0, 0, 0, NLMSG_SPACE(len) - sizeof(struct nlmsghdr), 0); 
 NETLINK_CB(skb).pid = 0; 
 NETLINK_CB(skb).dst_group = 0; 
 
 memcpy(NLMSG_DATA(nl), buf, len); 
 nl->nlmsg_len = (len > 2) ? (len - 2):len; 
 
 netlink_unicast(netlink_fd, skb, dest, MSG_DONTWAIT); 
 printk(KERN_ALERT "K send packet success\n"); 
} 
 
static int process_hello_get(int dest, void *buf, int len) 
{ 
 printk(KERN_ALERT "In process_hello get!\n"); 
 memcpy(buf, "I known you !", 13); 
 netlink_to_user(dest, buf, 13); 
 return NET_OK; 
} 
 
static int process_hello_set(int dest, void *buf, int len) 
{ 
 printk(KERN_ALERT "In process_hello set! %s\n", (char *)buf); 
 memcpy(buf, "S known you !", 13); 
 netlink_to_user(dest, buf, 13); 
 return NET_OK; 
} 
 
 
static void netlink_process_packet(struct nlmsghdr *nl) 
{ 
 int ret; 
 
 switch(nl->nlmsg_type) 
 { 
 case HELLO_GET: 
  ret = process_hello_get(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len); 
  break; 
 case HELLO_SET: 
  ret = process_hello_set(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len); 
  break; 
 default:break; 
 } 
} 
 
static void netlink_recv_packet(struct sk_buff *__skb) 
{ 
 struct sk_buff *skb; 
 struct nlmsghdr *nlhdr; 
 
 skb = skb_get(__skb); 
 if(skb->len >= sizeof(struct nlmsghdr)) 
 { 
  nlhdr = (struct nlmsghdr *)skb->data; 
  if(nlhdr->nlmsg_len >= sizeof(struct nlmsghdr) && 
    __skb->len >= nlhdr->nlmsg_len) 
  { 
   netlink_process_packet(nlhdr); 
  } 
 } 
 else 
  printk(KERN_ALERT "Kernel receive msg length error!\n"); 
} 
 
static int __init netlink_init(void) 
{ 
 netlink_fd = netlink_kernel_create(&init_net, USER_NETLINK_CMD, 0, netlink_recv_packet, NULL, THIS_MODULE); 
 if(NULL == netlink_fd) 
 { 
  printk(KERN_ALERT "Init netlink!\n"); 
  return -1; 
 } 
 printk(KERN_ALERT "Init netlink success!\n"); 
 return 0; 
} 
 
static void __exit netlink_exit(void) 
{ 
 netlink_kernel_release(netlink_fd); 
 printk(KERN_ALERT "Exit netlink!\n"); 
} 
 
module_init(netlink_init); 
module_exit(netlink_exit); 

4. ./netlink/usrlink.h


/* 
 * usrlink.h 
 * 
 * Created on: 2014 Qian ? � ?7 � ? *  Author: cr 
 */ 
#ifndef USRLINK_H_ 
#define USRLINK_H_ 
 
#define USER_NETLINK_CMD 25 
#define MAXMSGLEN   1024 
 
typedef enum error_e { 
 NET_ERROR, 
 NET_OK, 
 NET_PARAM, 
 NET_MEM, 
 NET_SOCK, 
} netlink_err; 
 
typedef enum module_e { 
 HELLO_CMD = 1, 
} netlink_module; 
 
typedef enum type_e { 
 HELLO_SET, 
 HELLO_GET, 
} netlink_type; 
 
#endif /* USRLINK_H_ */ 

5. ./netlink/Makefile


MOD_NAME := netlink 
 
$(MOD_NAME)-objs : netlink.o 
 
-include $(MODULES_ROOT_DIR)/rules.dir 
 
.PHONY: 

6. Compilation mode.

Makefile, ES116en. dir under Knetlink/, netlink. c, ES121en. h, Makefile under Knetlink/ Just execute Make in the Knetlink directory at compile time

The user program

Makefile of user program is not released here. I built the project directly under eclipse and compiled it automatically...

1. netlink.c


/* 
 * usrlink.c 
 * 
 * Created on: 2014 Qian ? � ?7 � ? *  Author: cr 
 */ 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include "usrlink.h" 
 
int netlink_sock_init(netlink_sock *netlink_s, int module, int protocol) 
{ 
 netlink_s->sock = socket(PF_NETLINK, SOCK_RAW, protocol); 
 if(netlink_s->sock < 0) 
  return NET_SOCK; 
 memset(&netlink_s->src, 0 ,sizeof(netlink_s->src)); 
 netlink_s->src.nl_family = AF_NETLINK; 
 netlink_s->src.nl_pid = module; 
 netlink_s->src.nl_groups = 0; 
 
 if(bind(netlink_s->sock, (struct sockaddr *)&netlink_s->src, sizeof(netlink_s->src)) < 0) 
  return NET_SOCK; 
 
 netlink_s->dest.nl_family = AF_NETLINK; 
 netlink_s->dest.nl_pid = 0; 
 netlink_s->dest.nl_groups = 0; 
 
 return NET_OK; 
} 
 
int netlink_send(netlink_sock *netlink_s, int type, char *sbuf, int slen, char *rbuf, int *rlen) 
{ 
 struct msghdr msg; 
 struct nlmsghdr *nlhdr = NULL; 
 struct iovec iov; 
 int ret; 
 
 nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAXMSGLEN)); 
 if(NULL == nlhdr) 
  return NET_MEM; 
 
 memcpy(NLMSG_DATA(nlhdr), sbuf, slen); 
 nlhdr->nlmsg_len = NLMSG_SPACE(slen); 
 nlhdr->nlmsg_pid = netlink_s->src.nl_pid; 
 nlhdr->nlmsg_type = type; 
 nlhdr->nlmsg_flags = 0; 
 
 iov.iov_base = (void *)nlhdr; 
 iov.iov_len = nlhdr->nlmsg_len; 
 
 msg.msg_name = (void *)&(netlink_s->dest); 
 msg.msg_namelen = sizeof(netlink_s->dest); 
 msg.msg_iov = &iov; 
 msg.msg_iovlen = 1; 
 
 ret = sendmsg(netlink_s->sock, &msg, 0); 
 if(ret < 0) 
 { 
  printf("Send fail\n"); 
  goto error; 
 } 
 ret = recvmsg(netlink_s->sock, &msg, 0); 
 if(ret < 0) 
 { 
  printf("Read fail\n"); 
  goto error; 
 } 
 memcpy(rbuf, NLMSG_DATA(nlhdr), nlhdr->nlmsg_len); 
 *rlen = nlhdr->nlmsg_len; 
 return NET_OK; 
 
error: 
 free(nlhdr); 
 return NET_SOCK; 
} 
 
int netlink_sock_deinit(netlink_sock *netlink_s) 
{ 
 close(netlink_s->sock); 
 memset(netlink_s, 0, sizeof(netlink_sock)); 
 return NET_OK; 
} 

2. netlink.h


/* 
 * usrlink.h 
 * 
 * Created on: 2014 *  Author: cr 
 */ 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <asm/types.h> 
#include <linux/socket.h> 
#include <linux/netlink.h> 
#ifndef USRLINK_H_ 
#define USRLINK_H_ 
 
#define USER_NETLINK_CMD 25 
#define MAXMSGLEN   1024 
 
typedef enum error_e { 
 NET_ERROR, 
 NET_OK, 
 NET_PARAM, 
 NET_MEM, 
 NET_SOCK, 
} netlink_err; 
 
typedef enum module_e { 
 HELLO_CMD = 1, 
} netlink_module; 
 
typedef enum type_e { 
 HELLO_SET, 
 HELLO_GET, 
} netlink_type; 
 
typedef struct usr_sock_h { 
 int sock; 
 struct sockaddr_nl dest; 
 struct sockaddr_nl src; 
} netlink_sock; 
 
int netlink_sock_init(netlink_sock *netlink_s, int module, int protocol); 
int netlink_sock_deinit(netlink_sock *netlink_s); 
int netlink_send(netlink_sock *netlink_s, int type, char *sbuf, int slen, char *rbuf, int *rlen); 
 
#endif /* USRLINK_H_ */ 

3. main.c


/* 
 * main.c 
 * 
 * Created on: 2014 Qian ? � ?7 � ? *  Author: cr 
 */ 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include "usrlink.h" 
 
int parse_ret(int ret) 
{ 
 switch(ret) 
 { 
 case NET_OK: 
  return ret; 
 case NET_ERROR: 
  printf("error\n"); 
  goto exit_p; 
 case NET_MEM: 
  printf("Memory error\n"); 
  goto exit_p; 
 case NET_PARAM: 
  printf("Param error\n"); 
  goto exit_p; 
 case NET_SOCK: 
  printf("Socket error\n"); 
  goto exit_p; 
 default:break; 
 } 
exit_p: 
 return NET_ERROR; 
} 
 
void usage(void) 
{ 
 printf("Usage: Netlink -G <param>\n\t-S <param>\n"); 
} 
 
int main(int argc, char **argv) 
{ 
 netlink_sock h_sock; 
 char rbuf[1024]; 
 char sbuf[1024]; 
 int ret, type, slen = 0, rlen = 0; 
 
 ret = netlink_sock_init(&h_sock, HELLO_CMD, USER_NETLINK_CMD); 
 if(NET_OK != parse_ret(ret)) 
  goto exit_p; 
 
 bzero(&rbuf, sizeof(rbuf)); 
 bzero(&sbuf, sizeof(sbuf)); 
 if(argc < 3) 
 { 
  usage(); 
  goto exit_p; 
 } 
 if(!strncmp("-G", argv[1], 2)) 
  type = HELLO_GET; 
 else if(!strncmp("-S", argv[1], 2)) 
  type = HELLO_SET; 
 
 strcpy(sbuf, argv[2]); 
 slen = strlen(sbuf); 
 ret = netlink_send(&h_sock, type, sbuf, slen, rbuf, &rlen); 
 if(NET_OK != parse_ret(ret)) 
  goto exit_p; 
 
 if(rlen > 0) 
 { 
  rbuf[rlen] = '\0'; 
  printf("K rep [len = %d]:%s\n", rlen, rbuf); 
 } 
 printf("K[len = %d]: %s\n", rlen, rbuf); 
 
exit_p: 
 netlink_sock_deinit(&h_sock); 
 return 0; 
} 

conclusion

That is the end of this article on linux user program and kernel communication details (netlink mechanism), I hope to help you. Interested friends can continue to refer to other related topics in this site, if there is any deficiency, welcome to comment out. Thank you for your support!


Related articles: