netlink demo

来源:互联网 发布:佛山房产网签数据 编辑:程序博客网 时间:2024/06/06 17:35

最近在学习linux netlink相关内容,发现这是一个用户空间和内核空间通信的好办法,于是写一个demo体验一下,一下代码基于linux kernel 3.19。

kernel mode的代码netlink_demo_kmode.c如下:

----------------------------------------------------------------------------------------------------------------

#include <linux/kernel.h>

#include <linux/module.h>

#include <net/net_namespace.h>

#include <linux/netlink.h>

#include <net/sock.h>

#define NETLINK_TEST 20

static struct sock *netlink_test_sk;

static void netlink_test_rcv(struct sk_buff *skb)

{

struct sk_buff *skb_in, *skb_out;

struct nlmsghdr *nlh;

char message[32] = {0};

int seq, pid;

unsigned int datalength;

skb_in = skb_get(skb);

if (skb_in->len >= nlmsg_total_size(0)) {

nlh = nlmsg_hdr(skb_in);

pid = nlh->nlmsg_pid;

seq = nlh->nlmsg_seq;

printk("message received from process %d: %s\n", pid, (char*)NLMSG_DATA(nlh));

sprintf(message, "hello, process %d", pid);

datalength = strlen(message) + 1;

skb_out = nlmsg_new(NLMSG_LENGTH(datalength), GFP_KERNEL);

nlh = nlmsg_put(skb_out, pid, seq, 0, NLMSG_ALIGN(datalength), 0);

memcpy(nlmsg_data(nlh), message, datalength);

netlink_unicast(netlink_test_sk, skb_out, pid, MSG_DONTWAIT);

}

kfree_skb(skb_in);

}

int __init netlink_test_init(void)

{

struct netlink_kernel_cfg cfg = {

.groups

= 0,

.input

= netlink_test_rcv,

};

netlink_test_sk = netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);

if (!netlink_test_sk)

return -ENOMEM;

return 0;

}

void __exit netlink_test_exit(void)

{

netlink_kernel_release(netlink_test_sk);

}

module_init(netlink_test_init);

module_exit(netlink_test_exit);

MODULE_LICENSE("GPL");

----------------------------------------------------------------------------------------------------------------

Makefile内容如下:

----------------------------------------------------------------------------------------------------------------

# To build modules outside of the kernel tree, we run "make"

# in the kernel source tree; the Makefile these then includes this

# Makefile once again.

# This conditional selects whether we are being included from the

# kernel Makefile or not.

ifeq ($(KERNELRELEASE),)

# Assume the source tree is where the running kernel was built

# You should set KERNELDIR in the environment if it's elsewhere

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

# The current directory is passed to sub-makes as argument

PWD := $(shell pwd)

default:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

rm -rf *.o *.mod.c *.mod.o *.symvers *.order

clean:

rm -rf *.ko

.PHONY: clean

else

# called from kernel build system: just declare what our modules are

obj-m := netlink_demo_kmode.o

endif

----------------------------------------------------------------------------------------------------------------

User mode的代码netlink_demo_umode.c如下:

----------------------------------------------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#include <sys/socket.h>

#include <string.h>

#include <linux/netlink.h>

#define NETLINK_TEST 20

#define MSG_LEN 100

int main(int argc, char* argv[])

{

char *data = "hello, kernel";

struct sockaddr_nl local, dest;

int skfd, ret;

unsigned int datalength, addrlength;

struct nlmsghdr *msg_out, *msg_in;

skfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_TEST);

if(skfd < 0){

perror("create socket failed");

return 0;

}

memset(&local, 0, sizeof(struct sockaddr_nl));

local.nl_family = AF_NETLINK;

local.nl_pid = getpid();

local.nl_groups = 0;

if(bind(skfd, (struct sockaddr *)&local, sizeof(struct sockaddr_nl)) != 0){

perror("bind failed");

close(skfd);

return 0;

}

memset(&dest, 0, sizeof(struct sockaddr_nl));

dest.nl_family = AF_NETLINK;

dest.nl_pid = 0;

dest.nl_groups = 0;

datalength = strlen(data) + 1;

msg_out = (struct nlmsghdr*)malloc(NLMSG_SPACE(datalength));

memset(msg_out, 0, NLMSG_SPACE(datalength));

msg_out->nlmsg_len = NLMSG_SPACE(datalength);

msg_out->nlmsg_flags = 0;

msg_out->nlmsg_type = 0;

msg_out->nlmsg_seq = 0;

msg_out->nlmsg_pid = local.nl_pid;

memcpy(NLMSG_DATA(msg_out), data, strlen(data));

ret = sendto(skfd, msg_out, msg_out->nlmsg_len, 0, (struct sockaddr*)&dest, sizeof(struct sockaddr_nl));

if(!ret){

perror("send failed");

free(msg_out);

close(skfd);

return 0;

}

free(msg_out);

msg_in = (struct nlmsghdr*)malloc(NLMSG_SPACE(MSG_LEN));

memset(msg_in, 0, NLMSG_SPACE(MSG_LEN));

addrlength = sizeof(struct sockaddr_nl);

ret = recvfrom(skfd, msg_in, NLMSG_SPACE(MSG_LEN), 0, (struct sockaddr*)&dest, &addrlength);

if(!ret){

perror("recv failed");

free(msg_in);

close(skfd);

return 0;

}

printf("message received from kernel: %s\n", (char*)NLMSG_DATA(msg_in));

free(msg_in);

close(skfd);

return 0;

}

分别编译kernel mode和user mode的代码,得到netlink_demo_kmode.ko和netlink_demo_umode两个文件,用insmod命令加载netlink_demo_kmode.ko后,运行netlink_demo_umode,效果如下:

/ # insmod netlink_demo_kmode.ko

/ # ./netlink_demo_umode

[ 14.258242] message received from process 951: hello, kernel

message received from kernel: hello, process 951

原创粉丝点击