Chinaunix

标题: 求助,netlink传输,内核死活收不到包 [打印本页]

作者: overcloud    时间: 2009-02-21 00:52
标题: 求助,netlink传输,内核死活收不到包
谢谢各位的帮助,代码改了一下现在可以从userspace像kernel发送并且成功收到了,但是kernel返回的消息userspace还是收不到,recvmsg 一直返回 0

内核代码如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/skbuff.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <net/sock.h>

#include <linux/types.h>
#include <linux/socket.h>
#include <linux/netlink.h>
#define MAX_PAYLOAD 1024
struct sock *nl_sk = NULL;
u32 pid = 0;

void nl_data_ready (struct sk_buff *skb)
{&nbsp;&nbsp;&nbsp;&nbsp;struct sk_buff *skb2 = NULL;
&nbsp;&nbsp;&nbsp;&nbsp;printk("input()called\n");
&nbsp;&nbsp;&nbsp;&nbsp;struct nlmsghdr *nlh = NULL;
&nbsp;&nbsp;&nbsp;&nbsp;nlh = (struct nlmsghdr *)skb->data;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printk("%s: received netlink message payload:%s\n",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__FUNCTION__, NLMSG_DATA(nlh));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pid = nlh->nlmsg_pid;
&nbsp;&nbsp;&nbsp;&nbsp;printk("pid = %d\n",pid);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(pid !=0){
&nbsp;&nbsp;&nbsp;&nbsp;skb2 = alloc_skb(NLMSG_SPACE(MAX_PAYLOAD),GFP_KERNEL);
&nbsp;&nbsp;&nbsp;&nbsp;printk("skb allocated\n");
&nbsp;&nbsp;&nbsp;&nbsp;nlh = (struct nlmsghdr *)skb2->data;
&nbsp;&nbsp;&nbsp;&nbsp;nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
&nbsp;&nbsp;&nbsp;&nbsp;nlh->nlmsg_pid = 0;
&nbsp;&nbsp;&nbsp;&nbsp;nlh->nlmsg_flags = 0;
&nbsp;&nbsp;&nbsp;&nbsp;strcpy(NLMSG_DATA(nlh),"Greeting From Kernel!");
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NETLINK_CB(skb2).pid = 0;
&nbsp;&nbsp;&nbsp;&nbsp;NETLINK_CB(skb2).dst_group = 0;
&nbsp;&nbsp;&nbsp;&nbsp;printk("ready to unicast\n");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(netlink_unicast(nl_sk, skb2, pid, MSG_DONTWAIT)<0)
&nbsp;&nbsp;&nbsp;&nbsp;printk("error unicast\n");
&nbsp;&nbsp;&nbsp;&nbsp;else printk("unicasted to pid:%u \n",pid);
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}//endif

&nbsp;&nbsp;
}
void netlink_test(){
&nbsp;
&nbsp;
&nbsp;//struct net net1;

&nbsp;nl_sk = netlink_kernel_create(&init_net,25,0,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nl_data_ready,NULL,THIS_MODULE);
&nbsp;if(nl_sk<0)
&nbsp;&nbsp;&nbsp;&nbsp;printk("error create sock\n");
&nbsp;else printk("successful create socket\n");

&nbsp;
}


static int my_module_init(void){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printk(KERN_INFO "initializing Netlink Socket!\n");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;netlink_test();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;
}
static void netlink_clear(void)
{&nbsp;&nbsp;&nbsp;&nbsp; sock_release(nl_sk->sk_socket);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printk(KERN_INFO"GOod Bye!\n");
}

module_init(my_module_init);
module_exit(netlink_clear);


userspace代码如下
#include <sys/socket.h>
#include <linux/netlink.h>
#include <iostream>
//#include <sys/socket.h>
#include <linux/types.h>
//#include <linux/netlink.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
using namespace std;
#define MAX_PAYLOAD 1024  /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
struct msghdr msg;

int main(){
std::cout<<("error bind")<<std::endl;
int sock_fd = socket(PF_NETLINK, SOCK_RAW,25);

if (sock_fd <0)
std::cout<<("error create socket!")<<std::endl;
memset(&src_addr, 0, sizeof(src_addr));

src_addr.nl_family = AF_NETLINK;     
src_addr.nl_pid = getpid();  /* self pid */
src_addr.nl_groups = 0;  /* not in mcast groups */
if (bind(sock_fd, (struct sockaddr*)&src_addr,sizeof(src_addr))<0)
        std::cout<<("error bind")<<std::endl;
else std::cout<<("binded")<<std::endl;

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=(struct nlmsghdr *)malloc(
                         NLMSG_SPACE(MAX_PAYLOAD));
/* Fill the netlink message header */
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid();  /* self pid */
nlh->nlmsg_flags = 0;
/* Fill in the netlink message payload */
strcpy((char *)NLMSG_DATA(nlh), "Hello you!");
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
printf("%d\n",iov.iov_len);
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;

if(sendmsg(sock_fd, &msg, 0) == -1){
        std::cout<<("error send")<<errno<<std::endl;
}
else std::cout<<("sent")<<std::endl;

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

printf("nlh set to be %s\n",NLMSG_DATA(nlh));
int ret = recvmsg(sock_fd, &msg, 0);
if( ret < 0)
        std::cout<<("error recv")<<errno<<std::endl;
else std::cout<<("received")<<ret<<std::endl;

printf("Received message payload:%s\n from kernel, length is %d\n",(char *)(NLMSG_DATA(nlh)),nlh->nlmsg_len);
   
/* Close Netlink Socket */
close(sock_fd);
}


[ 本帖最后由 overcloud 于 2009-2-27 16:39 编辑 ]
作者: duanjigang    时间: 2009-02-22 22:40
参考一个入门的例子修改下。
参考此文:
http://bbs3.chinaunix.net/viewthread.php?tid=1274437
作者: overcloud    时间: 2009-02-23 02:49
新的内核 netlink_kernel_create变成了下面的定义,谁知道struct net这里怎么用?
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);
作者: overcloud    时间: 2009-02-23 04:11
原帖由 duanjigang 于 2009-2-22 22:40 发表
参考一个入门的例子修改下。
参考此文:
http://bbs3.chinaunix.net/viewthread.php?tid=1274437


就是参照这些文档写的,但是新的kernel很多api变了,实在是搞不定,谁能帮着看下?
作者: overcloud    时间: 2009-02-23 06:20
。。

[ 本帖最后由 overcloud 于 2009-2-27 16:40 编辑 ]
作者: overcloud    时间: 2009-02-24 19:03
顶一下
作者: dreamice    时间: 2009-02-24 20:07
我建议你看看你跑程序的内核源代码,看一下具体API发生了哪些变化,然后对照着改一下API,应该差不多就能OK
作者: fly6    时间: 2009-02-25 10:12
你定义的RAW SOCKET ID号为25,内核其他地方有没有占用
作者: overcloud    时间: 2009-02-26 03:52
原帖由 fly6 于 2009-2-25 10:12 发表
你定义的RAW SOCKET ID号为25,内核其他地方有没有占用

你好,肯定没被占用,netlink.h里面才到20好像,我之前用netlink_firewall也是一样这种情况
作者: Godbach    时间: 2009-02-27 10:16
原帖由 overcloud 于 2009-2-23 02:49 发表
新的内核 netlink_kernel_create变成了下面的定义,谁知道struct net这里怎么用?
extern struct sock *netlink_kernel_create(struct net *net,
                                          int unit,unsigned int groups,
                                          void (*input)( ...


他的用法你可以参考一下ip_queue.c中是怎么使用的。
作者: Godbach    时间: 2009-02-27 10:18
内核模块的程序设计,你就参考2.6内核下ip_queue模块吧,很好用的,不是?
作者: overcloud    时间: 2009-02-27 16:41
谢谢各位的帮助,现在有了进展了,netlink_kernel_create搞定了,kernel显示收到内容了,但是从kernel unicast出去的msg用户态还是一直收不到,谁再帮着看看
作者: Godbach    时间: 2009-02-27 17:27
但是从kernel unicast出去的msg用户态还是一直收不到,


kernel unicast好像是要制定用户态的ID号的,这个地方指定了没有。
作者: Godbach    时间: 2009-02-27 17:50
ip_queue中向用户空间发送信息的函数:
static int
ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
                   unsigned int queuenum, void *data)
{

        int status = -EINVAL;
        struct sk_buff *nskb;
        struct ipq_queue_entry *entry;
        
        if (copy_mode == IPQ_COPY_NONE)
                return -EAGAIN;
        
        entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
        if (entry == NULL) {
                printk(KERN_ERR "ip_queue: OOM in ipq_enqueue_packet()\n");
                return -ENOMEM;
        }

        entry->info = info;
        entry->skb = skb;
        nskb = ipq_build_packet_message(entry, &status);
        if (nskb == NULL)
                goto err_out_free;
               
        write_lock_bh(&queue_lock);
        
        if (!peer_pid)
                goto err_out_free_nskb;

        if (queue_total >= queue_maxlen) {
                queue_dropped++;
                status = -ENOSPC;
                if (net_ratelimit())
                          printk (KERN_WARNING "ip_queue: full at %d entries, "
                                  "dropping packets(s). Dropped: %d\n", queue_total,
                                  queue_dropped);
                goto err_out_free_nskb;
        }

         /* netlink_unicast will either free the nskb or attach it to a socket */
        status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT);
        if (status < 0) {
                queue_user_dropped++;
                goto err_out_unlock;
        }

        __ipq_enqueue_entry(entry);

        write_unlock_bh(&queue_lock);
        return status;

err_out_free_nskb:
        kfree_skb(nskb);
        
err_out_unlock:
        write_unlock_bh(&queue_lock);

err_out_free:
        kfree(entry);
        return status;
}

其中红色那行代码就是实际的发送函数,这个函数里面peer_pid参数为用户空间发送消息是记录下来的,你比较一下是否是在内核接受用户消息时记录下来的。
作者: dreamice    时间: 2009-02-27 17:54
标题: 回复 #14 Godbach 的帖子
这个越研究越有意思啊,netlink也算快看明白了,呵呵
作者: overcloud    时间: 2009-02-27 18:07
原帖由 Godbach 于 2009-2-27 17:27 发表


kernel unicast好像是要制定用户态的ID号的,这个地方指定了没有。

恩,
这个我在userspace用getpid()获得了然后通过第一个从userspace发到kernel的消息里传给了内核
在内核代码里
pid = nlh->nlmsg_pid;
然后再用netlink_unicast的阿
作者: Godbach    时间: 2009-02-27 19:06
原帖由 dreamice 于 2009-2-27 17:54 发表
这个越研究越有意思啊,netlink也算快看明白了,呵呵


呵呵,一起研究,在讨论讨论更有意思哈。
作者: Godbach    时间: 2009-02-27 19:07
原帖由 overcloud 于 2009-2-27 18:07 发表

恩,
这个我在userspace用getpid()获得了然后通过第一个从userspace发到kernel的消息里传给了内核
在内核代码里
pid = nlh->nlmsg_pid;
然后再用netlink_unicast的阿


如果这样还收不到的话,你先确认一下内核中是否有包执行到了netlink_unicast函数。
作者: Godbach    时间: 2009-02-27 19:08
在调用netlink_unicast函数的前后打印一些信息出来,看看那些报文走到了这个流程,并且成功的被netlink_unicast处理了。
作者: springtty    时间: 2009-03-06 12:25
原帖由 Godbach 于 2009-2-27 19:08 发表
在调用netlink_unicast函数的前后打印一些信息出来,看看那些报文走到了这个流程,并且成功的被netlink_unicast处理了。

对,dmesg看看程序执行流程。

[ 本帖最后由 springtty 于 2009-3-6 12:33 编辑 ]
作者: overcloud    时间: 2009-03-06 20:46
dmesg显示是
[185112.322833] initializing Netlink Socket!
[185112.322851] successful create socket
[185118.182413] input()called
[185118.182428] nl_data_ready: received netlink message payload:Hello you!
[185118.182433] pid = 18160
[185118.182437] skb allocated
[185118.182441] Greeting From Kernel!
[185118.182444] ready to unicast
[185118.182451] unicasted
应该就是成功发出去了吧
作者: overcloud    时间: 2009-03-07 05:03
原帖由 Godbach 于 2009-2-27 17:50 发表
ip_queue中向用户空间发送信息的函数:

其中红色那行代码就是实际的发送函数,这个函数里面peer_pid参数为用户空间发送消息是记录下来的,你比较一下是否是在内核接受用户消息时记录下来的。


我看ip_queue.c里面并没有设置NETLINK_CB(skb),所以我把那两行去掉了,直接netlink_unicast,这次好像收到了,但是马上就机器崩溃,好像close(sock)那里出问题了,或者别的地方...依然一头雾水
作者: springtty    时间: 2009-03-07 13:19
原帖由 overcloud 于 2009-3-7 05:03 发表


我看ip_queue.c里面并没有设置NETLINK_CB(skb),所以我把那两行去掉了,直接netlink_unicast,这次好像收到了,但是马上就机器崩溃,好像close(sock)那里出问题了,或者别的地方...依然一头雾水


给你一段我的代码片段,我用NLMSG_PUT宏来设置参数。

NLMSG_PUT( skb_d, 0 , 0, 0, MAX_PAYLOAD );
NETLINK_CB( skb_d ).pid = 0;
nlh = nlmsg_hdr( skb_d );
memcpy( NLMSG_DATA( nlh ) ,  ptMsg , MAX_PAYLOAD );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
rc = netlink_unicast( nl_sk , skb_d, pid, MSG_DONTWAIT );

作者: springtty    时间: 2009-03-07 13:23
原帖由 overcloud 于 2009-3-7 05:03 发表


我看ip_queue.c里面并没有设置NETLINK_CB(skb),所以我把那两行去掉了,直接netlink_unicast,这次好像收到了,但是马上就机器崩溃,好像close(sock)那里出问题了,或者别的地方...依然一头雾水


用宏试试看。
#define NLMSG_NEW(skb, pid, seq, type, len, flags) \
({&nbsp;&nbsp;&nbsp;&nbsp;if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) \
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto nlmsg_failure; \
&nbsp;&nbsp;&nbsp;&nbsp;__nlmsg_put(skb, pid, seq, type, len, flags); })

#define NLMSG_PUT(skb, pid, seq, type, len) \
&nbsp;&nbsp;&nbsp;&nbsp;NLMSG_NEW(skb, pid, seq, type, len, 0)

作者: raysmile    时间: 2009-06-01 14:20
标题: 回复 #24 springtty 的帖子
你的方法很好用,我遇到类似的问题,使用了你的两段代码就解决问题了,从核心态发出的消息,用户态程序可以接收到了.非常感谢!




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2