免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1328 | 回复: 4

[内核入门] netlink释放的问题 [复制链接]

论坛徽章:
1
平安夜徽章
日期:2015-12-26 00:06:30
发表于 2016-08-23 11:43 |显示全部楼层
最近需要使用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 [last unloaded: netlink_k]
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 [netlink_k]
[<8004a964>] sys_delete_module+0x208/0x2a4
[<8000d9a4>] stack_done+0x20/0x3c

---[ end trace 777082ce045776f0 ]---
my netlink out!


代码如下:内核态:
  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/skbuff.h>
  4. #include <linux/init.h>
  5. #include <linux/ip.h>
  6. #include <linux/types.h>
  7. #include <linux/sched.h>
  8. #include <net/sock.h>
  9. #include <linux/netlink.h>        /*该文头文件里包含了linux/netlink.h,因为我们要用到net/netlink.h中的某些API函数,nlmsg_pug()*/
  10. #include <linux/version.h>

  11. #define MAX_MSGSIZE 1024

  12. MODULE_LICENSE("GPL");
  13. MODULE_AUTHOR("Koorey King");

  14. struct sock *nl_sk = NULL;
  15. //向用户空间发送消息的接口
  16. void sendnlmsg(char *message,int dstPID)
  17. {
  18.     struct sk_buff *skb;
  19.     struct nlmsghdr *nlh;
  20.     int len = NLMSG_SPACE(MAX_MSGSIZE);
  21.     int slen = 0;

  22.     if(!message || !nl_sk){
  23.         return;
  24.     }

  25.     // 为新的 sk_buffer申请空间
  26.     skb = alloc_skb(len, GFP_KERNEL);
  27.     if(!skb){
  28.         printk(KERN_ERR "my_net_link: alloc_skb Error./n");
  29.         return;
  30.     }

  31.     slen = strlen(message)+1;

  32.     //用nlmsg_put()来设置netlink消息头部
  33.     nlh = nlmsg_put(skb, 0, 0, 0, MAX_MSGSIZE, 0);

  34.     // 设置Netlink的控制块
  35.     NETLINK_CB(skb).pid = 0; // 消息发送者的id标识,如果是内核发的则置0
  36.     NETLINK_CB(skb).dst_group = 0; //如果目的组为内核或某一进程,该字段也置0

  37.     message[slen] = '\0';
  38.     memcpy(NLMSG_DATA(nlh), message, slen+1);

  39.     //通过netlink_unicast()将消息发送用户空间由dstPID所指定了进程号的进程
  40.     netlink_unicast(nl_sk,skb,dstPID,0);
  41.     printk("send OK!\n");
  42.     return;
  43. }
  44. static void nl_data_ready(struct sk_buff *pstSkb)
  45. {
  46.     struct sk_buff *skb;
  47.     struct nlmsghdr *pstNlHdr;

  48. #ifdef __DPI_KERNEL_DEBUG__
  49.     printk(KERN_ERR"dpi_netlink_recv_pkt in\n");
  50. #endif

  51.     skb = skb_get(pstSkb);
  52.     if(skb->len >= sizeof(struct nlmsghdr))
  53.     {
  54.         pstNlHdr = (struct nlmsghdr *)skb->data;
  55.         if((pstNlHdr->nlmsg_len >= sizeof(struct nlmsghdr)) &&
  56.                 (pstSkb->len >= pstNlHdr->nlmsg_len))
  57.         {
  58.             printk("%s: received netlink message payload: %s \n", __FUNCTION__, (char*)NLMSG_DATA(pstNlHdr));
  59.             sendnlmsg("I see you",pstNlHdr->nlmsg_pid); //发送者的进程ID我们已经将其存储在了netlink消息头部里的nlmsg_pid字段里,所以这里可以拿来用。
  60.                 printk("recvied finished!\n");
  61.         }
  62.     }
  63.     else
  64.     {
  65.         printk(KERN_ALERT "Kernel receive msg length error!\n");
  66.     }

  67. #ifdef __DPI_KERNEL_DEBUG__
  68.         printk(KERN_ERR"dpi_netlink_recv_pkt out\n");
  69. #endif

  70.     return;
  71. }

  72. static int __init myinit_module(void)
  73. {
  74.     printk("my netlink in\n");
  75.     nl_sk = netlink_kernel_create(&init_net,25,0,nl_data_ready,NULL,THIS_MODULE);
  76.     return 0;
  77. }

  78. static void __exit mycleanup_module(void)
  79. {
  80.         #if(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25))
  81.         netlink_kernel_release(nl_sk);
  82.     #else
  83.         sock_release(nl_sk->sk_socket);
  84.     #endif
  85.        
  86.     printk("my netlink out!\n");
  87. }

  88. module_init(myinit_module);
  89. module_exit(mycleanup_module);
复制代码

用户态:
  1. #include <sys/stat.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <sys/socket.h>
  6. #include <sys/types.h>
  7. #include <string.h>
  8. #include <asm/types.h>
  9. #include <linux/netlink.h>
  10. #include <linux/socket.h>

  11. #define MAX_PAYLOAD 1024 /*消息最大负载为1024字节*/

  12. int main(int argc, char* argv[])
  13. {
  14.     struct sockaddr_nl dest_addr;
  15.     struct nlmsghdr *nlh = NULL;
  16.     int sock_fd=-1;

  17.     if(-1 == (sock_fd=socket(PF_NETLINK, SOCK_RAW,25))){
  18.           perror("can't create netlink socket!");
  19.           return 1;
  20.     }
  21.     memset(&dest_addr, 0, sizeof(dest_addr));
  22.     dest_addr.nl_family = AF_NETLINK;
  23.     dest_addr.nl_pid = 0; /*我们的消息是发给内核的*/
  24.     dest_addr.nl_groups = 0; /*在本示例中不存在使用该值的情况*/

  25.    if(NULL == (nlh=(struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)))){
  26.           perror("alloc mem failed!");
  27.           return 1;
  28.    }
  29.    memset(nlh,0,MAX_PAYLOAD);
  30.    /* 填充Netlink消息头部 */
  31.    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
  32.    nlh->nlmsg_pid = getpid();//我们希望得到内核回应,所以得告诉内核我们ID号
  33.    nlh->nlmsg_type = NLMSG_NOOP; //指明我们的Netlink是消息负载是一条空消息
  34.    nlh->nlmsg_flags = 0;

  35.    /*设置Netlink的消息内容,来自我们命令行输入的第一个参数*/
  36.    strcpy(NLMSG_DATA(nlh), argv[1]);

  37.    sendto(sock_fd,nlh,NLMSG_LENGTH(MAX_PAYLOAD),0,(struct sockaddr*)(&dest_addr),sizeof(dest_addr));
  38.         
  39.    //接收内核消息的消息
  40.    printf("waiting message from kernel!\n");
  41.    
  42.    memset(nlh,0,MAX_PAYLOAD); //清空整个Netlink消息头包括消息头和负载
  43.    
  44.    recvfrom(sock_fd,nlh,NLMSG_LENGTH(MAX_PAYLOAD),0,(struct sockaddr*)(&dest_addr),NULL);
  45.    printf("Got response: %s\n",NLMSG_DATA(nlh));

  46.    /* 关闭netlink套接字 */
  47.    close(sock_fd);
  48.    free(nlh);
  49.    return 0;
  50. }
复制代码








论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
发表于 2016-08-27 20:28 |显示全部楼层
netlink_sock_destruct有几个WARN_ON,看看是命中哪一个了?

论坛徽章:
1
平安夜徽章
日期:2015-12-26 00:06:30
发表于 2016-08-29 21:24 |显示全部楼层
回复 2# nswcfd


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

论坛徽章:
0
发表于 2016-09-04 22:48 |显示全部楼层
楼主用的内核是哪个版本?

论坛徽章:
1
平安夜徽章
日期:2015-12-26 00:06:30
发表于 2016-09-09 14:37 |显示全部楼层
回复 4# xitry

Linux (none) 2.6.31--LSDK-9.2.0_U10.1020
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP