linux netlink 用法,Linux下netlink编程示例

在 Linux 2.4 版以后版本的内核中,几乎全部的中断过程与用户态进程的通信都是使用 netlink

套接字实现的,同时还使用 netlink 实现了 ip queue 工具,但 ip queue

的使用有其局限性,不能自由地用于各种中断过程。内核的帮助文档和其他一些 Linux 相关文章都没有对 netlink

套接字在中断过程和用户空间通信的应用上作详细的说明,使得很多用户对此只有一个模糊的概念。

Unicast Communication between Kernel and Application

在下面的例子中,一个用户空间进程发送一个netlink消息给内核模块,内核模块应答一个消息给发送进程,这里是用户空间的代码:

#include

#include

#define MAX_PAYLOAD 1024 struct sockaddr_nl src_addr, dest_addr;

struct msghdr msg;

struct nlmsghdr *nlh = NULL;

struct iovec iov;

int sock_fd;

void main() ...{

sock_fd = socket(PF_NETLINK,

SOCK_RAW,NETLINK_TEST);

memset(&src_addr, 0,

sizeof(src_addr));

src__addr.nl_family =

AF_NETLINK; src_addr.nl_pid =

getpid(); src_addr.nl_groups = 0; bind(sock_fd, (struct

sockaddr*)&src_addr,

sizeof(src_addr));

memset(&dest_addr, 0,

sizeof(dest_addr));

dest_addr.nl_family = AF_NETLINK;

dest_addr.nl_pid =

0; dest_addr.nl_groups = 0;

nlh=(struct nlmsghdr *)malloc(

NLMSG_SPACE(MAX_PAYLOAD));

nlh->nlmsg_len =

NLMSG_SPACE(MAX_PAYLOAD);

nlh->nlmsg_pid =

getpid(); nlh->nlmsg_flags = 0;

strcpy(NLMSG_DATA(nlh), "Hello you!");

iov.iov_base = (void *)nlh;

iov.iov_len =

nlh->nlmsg_len;

msg.msg_name = (void

*)&dest_addr;

msg.msg_namelen = sizeof(dest_addr);

msg.msg_iov = &iov;

msg.msg_iovlen = 1;

sendmsg(fd, &msg, 0);

memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));

recvmsg(fd, &msg, 0);

printf(" Received message payload: %s ",

NLMSG_DATA(nlh));

close(sock_fd);

} 这里是内核代码:

struct sock *nl_sk = NULL;

void nl_data_ready (struct sock *sk, int len)

...{

wake_up_interruptible(sk->sleep);

}

void netlink_test() ...{

struct sk_buff *skb = NULL;

struct nlmsghdr *nlh = NULL;

int err;

u32

pid; nl_sk = netlink_kernel_create(NETLINK_TEST,

nl_data_ready);

skb = skb_recv_datagram(nl_sk, 0, 0,

&err);

nlh = (struct nlmsghdr

*)skb->data;

printk("%s: received netlink message payload:%s

",

__FUNCTION__, NLMSG_DATA(nlh));

pid = nlh->nlmsg_pid;

NETLINK_CB(skb).groups = 0;

NETLINK_CB(skb).pid =

0; NETLINK_CB(skb).dst_pid = pid;

NETLINK_CB(skb).dst_groups =

0; netlink_unicast(nl_sk, skb, pid,

MSG_DONTWAIT);

sock_release(nl_sk->socket);

}

在内核模块被加载到内核,当我们运行用户程序,我们将看到下面的信息:

Received message payload: Hello you!

然后用dmesg我们可以看到内核输出:

netlink_test: received netlink message payload:

Hello you!

Multicast Communication between Kernel and Applications

这个例子中,两个应用程序在监听同一个netlink广播组.内核模块发送一个netlink消息给这个广播组,所用的应用程序都收到它,如下是用户程序代码:

#include

#include

#define MAX_PAYLOAD 1024 struct sockaddr_nl src_addr, dest_addr;

struct nlmsghdr *nlh = NULL;

struct iovec iov;

int sock_fd;

void main() ...{

sock_fd=socket(PF_NETLINK, SOCK_RAW,

NETLINK_TEST);

memset(&src_addr, 0,

sizeof(local_addr));

src_addr.nl_family =

AF_NETLINK; src_addr.nl_pid =

getpid(); src_addr.nl_groups = 1;

bind(sock_fd, (struct

sockaddr*)&src_addr,

sizeof(src_addr));

memset(&dest_addr, 0,

sizeof(dest_addr));

nlh = (struct nlmsghdr *)malloc(

NLMSG_SPACE(MAX_PAYLOAD));

memset(nlh, 0,

NLMSG_SPACE(MAX_PAYLOAD)); iov.iov_base = (void *)nlh;

iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);

msg.msg_name = (void

*)&dest_addr;

msg.msg_namelen = sizeof(dest_addr);

msg.msg_iov = &iov;

msg.msg_iovlen = 1;

printf("Waiting for message from kernel ");

recvmsg(fd, &msg, 0);

printf(" Received message payload: %s ",

NLMSG_DATA(nlh));

close(sock_fd);

} 内核代码:

#define MAX_PAYLOAD 1024

struct sock *nl_sk = NULL;

void netlink_test() ...{

sturct sk_buff *skb = NULL;

struct nlmsghdr *nlh;

int err;

nl_sk = netlink_kernel_create(NETLINK_TEST,

nl_data_ready);

skb=alloc_skb(NLMSG_SPACE(MAX_PAYLOAD),GFP_KERNEL);

nlh = (struct nlmsghdr

*)skb->data;

nlh->nlmsg_len =

NLMSG_SPACE(MAX_PAYLOAD);

nlh->nlmsg_pid =

0; nlh->nlmsg_flags = 0;

strcpy(NLMSG_DATA(nlh), "Greeting from

kernel!");

NETLINK_CB(skb).groups = 1;

NETLINK_CB(skb).pid = 0; NETLINK_CB(skb).dst_pid =

0; NETLINK_CB(skb).dst_groups = 1;

netlink_broadcast(nl_sk, skb, 0, 1,

GFP_KERNEL);

sock_release(nl_sk->socket);

} 我们运行用户程序:

./nl_recv &

Waiting for message from kernel

./nl_recv &

Waiting for message from kernel

然后我们加载内核模块到内核空间,会看到如下信息::

Received message payload: Greeting from kernel!

Received message payload: Greeting from kernel!

以下是一个简单的测试内核事件的应用程序:

#define

MAX_PAYLOAD 1024

struct

sockaddr_nl src_addr, dest_addr;

char *KernelMsg = NULL;

struct iovec iov;

int sock_fd;

struct msghdr msg;

int msglen;

#define

DEVICE_ADD "add"

#define

DEVICE_REMOVE "remove"

#define

DEVICE_NAME "event0"

#define

DEVICE_NAMELEN 6

void * DeviceManagement(void *arg)

...{

sock_fd =

socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);

int

msgle;

memset(&src_addr, 0, sizeof(src_addr));

src_addr.nl_family = AF_NETLINK;

src_addr.nl_pid = pthread_self() <<

16 | getpid();

src_addr.nl_groups = 1;

bind(sock_fd, (struct sockaddr *)&src_addr,

sizeof(src_addr));

memset(&dest_addr, 0, sizeof(dest_addr));

KernelMsg =

(struct nlmsghdr *)malloc(MAX_PAYLOAD);

memset(KernelMsg,

0, MAX_PAYLOAD);

iov.iov_base

= (void *)KernelMsg;

iov.iov_len

= MAX_PAYLOAD;

msg.msg_name

= (void *)&dest_addr;

msg.msg_namelen = sizeof(dest_addr);

msg.msg_iov

= &iov;

msg.msg_iovlen = 1;

while(1)

...{

//printf("Waiting for message from kernel ");

recvmsg(sock_fd, &msg, 0);

//printf("Receved message payload: %s ", KernelMsg);

msglen = strlen(KernelMsg);

//printf("Device: %s ", KernelMsg+msglen-DEVICE_NAMELEN);

if(!strncmp(DEVICE_NAME, KernelMsg+msglen-DEVICE_NAMELEN,

DEVICE_NAMELEN)) ...{

if(!strncmp(DEVICE_ADD, KernelMsg, strlen(DEVICE_ADD)))

...{

printf("Add event0 device ");

USBKeyboardReady = 1;

}

else if(!strncmp(DEVICE_REMOVE, KernelMsg, strlen(DEVICE_REMOVE)))

...{

printf("Remove event0 device ");

USBKeyboardReady = 0;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值