netlink释放的问题
最近需要使用netlink在用户态和内核态进行交互,可是在模块卸载时总是有个警告,不是太清楚怎样才能避免这个警告,还请大神们给点建议!先加载模块:
# insmod netlink_k.ko
执行用户态程序:
# ./netlink_user "hello world!"
打印:
waiting message from kernel!
Got response: I see you
dmesg查看内核打印:
# dmesg
nl_data_ready: received netlink message payload: hello world!
send OK!
recvied finished!
再卸载模块:
# rmmod netlink_k.ko
dmesg查看就会有如下的信息:
------------[ cut here ]------------
WARNING: at net/netlink/af_netlink.c:164 netlink_sock_destruct+0x80/0xcc()
Modules linked in: netlink_k(-) lc_ether usbserial bw_list cls_fw cls_basic sch_tbf sch_prio sch_htb sch_sfq sch_red sch_cbq xt_DSCP pppoe_l2tp pppol2tp ppp_async crc_ccitt pppoe pppox ppp_deflate bsd_comp ppp_generic slhc ts userm ebtable_filter ebtables xt_mac ipt_REDIRECT xt_CONNMARK xt_connmark xt_MARK xt_mark iptable_mangle xt_string iptable_filter iptable_nat ipt_MASQUERADE nf_nat nf_conntrack_ipv4 nf_conntrack nf_defrag_ipv4 ip_tables xt_tcpudp x_tables locator ath_pktlog(P) umac ath_dev(P) ath_rate_atheros(P) ath_rate_gbcom(P) ath_hal(P) adf(P) asf(P) ipv6 flowctrl bridge stp llc button led usb_storage sd_mod sg scsi_wait_scan scsi_mod ohci_hcd ehci_hcd usbcore gpioex gpio wdt boardinfo phy athrs_gmac bb nvram
Call Trace:
[<801e6e30>] dump_stack+0x8/0x34
[<8002383c>] warn_slowpath_common+0x70/0xb0
[<8018d064>] netlink_sock_destruct+0x80/0xcc
[<801693b8>] __sk_free+0x24/0xf8
[<826cd260>] mycleanup_module+0x20/0x3c
[<8004a964>] sys_delete_module+0x208/0x2a4
[<8000d9a4>] stack_done+0x20/0x3c
---[ end trace 777082ce045776f0 ]---
my netlink out!
代码如下:内核态:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/ip.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <net/sock.h>
#include <linux/netlink.h> /*该文头文件里包含了linux/netlink.h,因为我们要用到net/netlink.h中的某些API函数,nlmsg_pug()*/
#include <linux/version.h>
#define MAX_MSGSIZE 1024
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Koorey King");
struct sock *nl_sk = NULL;
//向用户空间发送消息的接口
void sendnlmsg(char *message,int dstPID)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
int len = NLMSG_SPACE(MAX_MSGSIZE);
int slen = 0;
if(!message || !nl_sk){
return;
}
// 为新的 sk_buffer申请空间
skb = alloc_skb(len, GFP_KERNEL);
if(!skb){
printk(KERN_ERR "my_net_link: alloc_skb Error./n");
return;
}
slen = strlen(message)+1;
//用nlmsg_put()来设置netlink消息头部
nlh = nlmsg_put(skb, 0, 0, 0, MAX_MSGSIZE, 0);
// 设置Netlink的控制块
NETLINK_CB(skb).pid = 0; // 消息发送者的id标识,如果是内核发的则置0
NETLINK_CB(skb).dst_group = 0; //如果目的组为内核或某一进程,该字段也置0
message = '\0';
memcpy(NLMSG_DATA(nlh), message, slen+1);
//通过netlink_unicast()将消息发送用户空间由dstPID所指定了进程号的进程
netlink_unicast(nl_sk,skb,dstPID,0);
printk("send OK!\n");
return;
}
static void nl_data_ready(struct sk_buff *pstSkb)
{
struct sk_buff *skb;
struct nlmsghdr *pstNlHdr;
#ifdef __DPI_KERNEL_DEBUG__
printk(KERN_ERR"dpi_netlink_recv_pkt in\n");
#endif
skb = skb_get(pstSkb);
if(skb->len >= sizeof(struct nlmsghdr))
{
pstNlHdr = (struct nlmsghdr *)skb->data;
if((pstNlHdr->nlmsg_len >= sizeof(struct nlmsghdr)) &&
(pstSkb->len >= pstNlHdr->nlmsg_len))
{
printk("%s: received netlink message payload: %s \n", __FUNCTION__, (char*)NLMSG_DATA(pstNlHdr));
sendnlmsg("I see you",pstNlHdr->nlmsg_pid); //发送者的进程ID我们已经将其存储在了netlink消息头部里的nlmsg_pid字段里,所以这里可以拿来用。
printk("recvied finished!\n");
}
}
else
{
printk(KERN_ALERT "Kernel receive msg length error!\n");
}
#ifdef __DPI_KERNEL_DEBUG__
printk(KERN_ERR"dpi_netlink_recv_pkt out\n");
#endif
return;
}
static int __init myinit_module(void)
{
printk("my netlink in\n");
nl_sk = netlink_kernel_create(&init_net,25,0,nl_data_ready,NULL,THIS_MODULE);
return 0;
}
static void __exit mycleanup_module(void)
{
#if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25))
netlink_kernel_release(nl_sk);
#else
sock_release(nl_sk->sk_socket);
#endif
printk("my netlink out!\n");
}
module_init(myinit_module);
module_exit(mycleanup_module);
用户态:
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/socket.h>
#define MAX_PAYLOAD 1024 /*消息最大负载为1024字节*/
int main(int argc, char* argv[])
{
struct sockaddr_nl dest_addr;
struct nlmsghdr *nlh = NULL;
int sock_fd=-1;
if(-1 == (sock_fd=socket(PF_NETLINK, SOCK_RAW,25))){
perror("can't create netlink socket!");
return 1;
}
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /*我们的消息是发给内核的*/
dest_addr.nl_groups = 0; /*在本示例中不存在使用该值的情况*/
if(NULL == (nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)))){
perror("alloc mem failed!");
return 1;
}
memset(nlh,0,MAX_PAYLOAD);
/* 填充Netlink消息头部 */
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid();//我们希望得到内核回应,所以得告诉内核我们ID号
nlh->nlmsg_type = NLMSG_NOOP; //指明我们的Netlink是消息负载是一条空消息
nlh->nlmsg_flags = 0;
/*设置Netlink的消息内容,来自我们命令行输入的第一个参数*/
strcpy(NLMSG_DATA(nlh), argv);
sendto(sock_fd,nlh,NLMSG_LENGTH(MAX_PAYLOAD),0,(struct sockaddr*)(&dest_addr),sizeof(dest_addr));
//接收内核消息的消息
printf("waiting message from kernel!\n");
memset(nlh,0,MAX_PAYLOAD); //清空整个Netlink消息头包括消息头和负载
recvfrom(sock_fd,nlh,NLMSG_LENGTH(MAX_PAYLOAD),0,(struct sockaddr*)(&dest_addr),NULL);
printf("Got response: %s\n",NLMSG_DATA(nlh));
/* 关闭netlink套接字 */
close(sock_fd);
free(nlh);
return 0;
}
netlink_sock_destruct有几个WARN_ON,看看是命中哪一个了? 回复 2# nswcfd
非常感谢指点,原来是neilink内核态接收时没有kfree_skb释放掉接收回调的入参skb,在卸载时就会触发警告,第一次用netlink,所以模仿了网上的一些代码,然而并不清楚有什么bug在里面。多谢了~{:yct68:} {:yct68:} 楼主用的内核是哪个版本? 回复 4# xitry
Linux (none) 2.6.31--LSDK-9.2.0_U10.1020
页:
[1]