没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
Linux 中与内核通信的 Netlink机制
Netlink在 2.6版本的内核中变化也是很大的,在最新的,其定义已经改成下面这种形式,传
递的参数已经达到 6 个。其中第一个参数和 mutex 参数都是最新添加的。Mutex 也可以为空。
这里主要是关于内核空间中的 netlink函数的使用。
extern struct sock *netlink_kernel_create(struct net *net,
int unit,unsigned int groups,
void (*input)(struct sk_buff *skb),
struct mutex *cb_mutex,
struct module *module);
struct net是一个网络名字空间 namespace,在不同的名字空间里面可以有自己的转发信息
库,有自己的一套 net_device等等。默认情况下都是使用 init_net这个全局变量,下面是内
核中调用 netlink_kernel_create()函数的一个示例。
在内核中,
audit_sock = netlink_kernel_create(&init_net, NETLINK_AUDIT, 0,
audit_receive, NULL, THIS_MODULE);
模块调用函数 netlink_unicast来发送单播消息: intnetlink_unicast(structsock *ssk,struct
sk_buff *skb, u32 pid, int nonblock)
参数 ssk为函数 netlink_kernel_create()返回的 socket,参数 skb 存放消息,它的 data字
段指向要发送的 netlink消息结构,而 skb 的控制块保存了消息的地址信息,前面的宏
NETLINK_CB(skb) 就用于方便设置该控制块,参数 pid为接收消息进程的 pid,参数 nonblock
表示该函数是否为非阻塞,如果为1,该函数将在没有接收缓存可利用时立即返回,而如果
为 0,该函数在没有接收缓存可利用 定时睡眠。
netlink的内核实现在.c文件 net/core/af_netlink.c中,内核模块要想使用 netlink,也必须
包含头文件 linux/netlink.h。内核使用 netlink需要专门的 API,这完全不同于用户态应用对
netlink的使用。如果用户需要增加新的 netlink协议类型,必须通过修改 linux/netlink.h来实
现,当然,目前的 netlink实现已经包含了一个通用的协议类型 NETLINK_GENERIC 以方便
用户使用,用户可以直接使用它而不必增加新的协议类型。前面讲到,为了增加新的 netlink
协议类型,用户仅需增加如下定义到 linux/netlink.h就可以:
只要增加这个定义之后,用户就可以在内核的任何地方引用该协议。
在内核中,为了创建一个 netlink socket用户需要调用如下函数:
extern struct sock *netlink_kernel_create(struct net *net,
int unit,unsigned int groups,
void (*input)(struct sk_buff *skb),
struct mutex *cb_mutex,
struct module *module);
struct net是一个网络名字空间 namespace,在不同的名字空间里面可以有自己的转发信息库,
有自己的一套 net_device等等。默认情况下都是使用 init_net这个全局变量
参数 unit表示 netlink协议类型,如 NETLINK_MYTEST ,参数 input则为内核模块定
义的 netlink消息处理函数,当有消息到达这个 netlink socket时,该 input函数指针就会被引
用。函数指针 input的参数 skb实际上就是函数 netlink_kernel_create返回的 struct sock指针,
sock 实际是 socket的一个内核表示数据结构,用户态应用创建的 socket在内核中也会有一
个 struct sock结构来表示。
函数 input()会在发送进程执行 sendmsg()时被调用,这样处理消息比较及时,但是,如
1
果消息特别长时,这样处理将增加系统调用 sendmsg()的执行时间,也就是说当用户的程序
调用 sendmsg ()函数时,如果 input()函数处理时间过长,也就是说 input()函数不执行不完,
用户程序调用的 sendmsg()函数就不会返回。只有当内核空间中的 input()函数返回时,用户
调用的 sendmsg()函数才会返回。对于这种情况,可以定义一个内核线程专门负责消息接收,
而函数 input的工作只是唤醒该内核线程,这样 sendmsg 将很快返回。(这里网上的的说明)
不过在查看,一般都是按下面的方法进行处理。
这里注册的 netlink协议为 NETLINK_XFRM 。
nlsk = netlink_kernel_create(net, NETLINK_XFRM, XFRMNLGRP_MAX,
xfrm_netlink_rcv, NULL, THIS_MODULE);
static void xfrm_netlink_rcv(struct sk_buff *skb)
{
mutex_lock(&xfrm_cfg_mutex);
netlink_rcv_skb(skb, &xfrm_user_rcv_msg);
mutex_unlock(&xfrm_cfg_mutex);
}
在 netlink_rcv_skb()函数中进行接收处理。
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
u32 group, gfp_t allocation)
前面的三个参数与 netlink_unicast相同,参数 group为接收消息的多播组,该参数的每
一个位代表一个多播组,因此如果发送给多个多播组,就把该参数设置为多个多播组组 ID
的位或。参数 allocation为内核内存分配类型,一般地为 GFP_ATOMIC 或 GFP_KERNEL ,
GFP_ATOMIC 用于原子的上下文(即不可以睡眠),而 GFP_KERNEL 用于非原子上下文。
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_pid = 0;
NETLINK_CB(skb).dst_group = 1;
字段 pid表示消息发送者进程 ID,也即源地址,对于内核,它为 0, dst_pid表示消息
接收者进程 ID,也即目标地址,如果目标为组或内核,它设置为 0,否则 dst_group表示
目标组地址,如果它目标为某一进程或内核,dst_group应当设置为 0。
下面是参考网上使用 netlink写的和内核通信的两个程序,一个是用户空间,一个是内核
空间。
内核空间:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/types.h>
#include <net/sock.h>
#include <net/netlink.h>
#define NETLINK_TEST 25
#define MAX_MSGSIZE 1024
int stringlength(char *s);
void sendnlmsg(char * message);
int pid;
int err;
2
struct sock *nl_sk = NULL;
int flag = 0;
void sendnlmsg(char *message)
{
struct sk_buff *skb_1;
struct nlmsghdr *nlh;
int len = NLMSG_SPACE(MAX_MSGSIZE);
int slen = 0;
if(!message || !nl_sk)
{
return ;
}
skb_1 = alloc_skb(len,GFP_KERNEL);
if(!skb_1)
{
printk(KERN_ERR "my_net_link:alloc_skb_1 error\n");
}
slen = stringlength(message);
nlh = nlmsg_put(skb_1,0,0,0,MAX_MSGSIZE,0);
NETLINK_CB(skb_1).pid = 0;
NETLINK_CB(skb_1).dst_group = 0;
message[slen]= '\0';
memcpy(NLMSG_DATA(nlh),message,slen+1);
printk("my_net_link:send message '%s'.\n",(char *)NLMSG_DATA(nlh));
netlink_unicast(nl_sk,skb_1,pid,MSG_DONTWAIT);
}
int stringlength(char *s)
{
int slen = 0;
for(; *s; s++){
slen++;
}
return slen;
}
void nl_data_ready(struct sk_buff *__skb)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
char str[100];
struct completion cmpl;
int i=10;
skb = skb_get (__skb);
if(skb->len >= NLMSG_SPACE(0))
{
3
剩余15页未读,继续阅读
资源评论
- 宋永春(Chauncy)2023-09-20资源值得借鉴的内容很多,那就浅学一下吧,值得下载!
G11176593
- 粉丝: 6646
- 资源: 3万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功