Rayree1993 发表于 2016-08-23 11:43

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;
}








nswcfd 发表于 2016-08-27 20:28

netlink_sock_destruct有几个WARN_ON,看看是命中哪一个了?

Rayree1993 发表于 2016-08-29 21:24

回复 2# nswcfd


非常感谢指点,原来是neilink内核态接收时没有kfree_skb释放掉接收回调的入参skb,在卸载时就会触发警告,第一次用netlink,所以模仿了网上的一些代码,然而并不清楚有什么bug在里面。多谢了~{:yct68:} {:yct68:}

xitry 发表于 2016-09-04 22:48

楼主用的内核是哪个版本?

Rayree1993 发表于 2016-09-09 14:37

回复 4# xitry

Linux (none) 2.6.31--LSDK-9.2.0_U10.1020
页: [1]
查看完整版本: netlink释放的问题