如何在内核态将网络接口加入多播组
时间:2010-07-22
来源:互联网
本帖最后由 lion3875 于 2010-07-22 16:45 编辑
我们可以在用户态通过socket接口,将一个本地网络接口加入某个多播组,通常是调用setsockopt,并使用IP_ADD_MEMBERSHIP参数,如:
..........
imr.imr_multiaddr.s_addr = netAddr.s_addr;
imr.imr_interface.s_addr = interfaceAddr.s_addr;
setsockopt(netPath->eventSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq);
.......... (此代码可以工作,经测试可以接收发往多播组的数据)
可是如果在自己的一个内核模块里,如何让本地网络接口加入某个多播组呢,我自己写了一个内核模块,希望在模块加载的时候,使本地网络接口加入一个组播地址(IEEE1588的多播地址 - 224.0.1.129),可是失败了,代码片段如下:
/* initialize a kernel socket which used to control eth */
sock_create_kern(PF_INET, SOCK_DGRAM, 0, &privdata->sock);
strcpy(privdata->ifr.ifr_ifrn.ifrn_name, IF_NAME);
kernel_sock_ioctl(privdata->sock, SIOCSIFNAME, (unsigned long) &privdata->ifr);
kernel_sock_ioctl(privdata->sock, SIOCGIFADDR, (unsigned long) &privdata->ifr);
ieee1588_ntoa(&privdata->ifr.ifr_ifru.ifru_addr, local_ipaddr);
printk("Local IP Addr: %s\n", local_ipaddr);
printk("Multicast IP Addr: %s\n", DEFAULT_PTP_DOMAIN_ADDRESS);
imr.imr_multiaddr.s_addr = in_aton(DEFAULT_PTP_DOMAIN_ADDRESS);
imr.imr_interface.s_addr = in_aton(local_ipaddr);
ret = kernel_setsockopt(privdata->sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &imr.imr_interface.s_addr, sizeof(struct in_addr));
if (ret) {
printk("set Multicast option failed.\n"
;
}
ret = kernel_setsockopt(privdata->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq));
if (ret) {
printk("set Multicast option failed.\n"
;
}
虽然kernel_setsockopt没有返回错误(返回0),但是本地网络接口eth0仍然无法收到发送给这个多播地址的网络数据(只能收单播)
曾经考虑过将网卡初始化为混杂模式,去收多播数据,可那不是正确的做法,太占CPU资源,正确的做法应该是加入多播组
请大家一起思考一下,怎样才能实现在内核模块里,将本地网络接口(如eth0)加入某个多播组呢,有没有其它更好的方法去接收多播数据呢(除了混杂模式,因为我并不希望做一个嗅探器)
我们可以在用户态通过socket接口,将一个本地网络接口加入某个多播组,通常是调用setsockopt,并使用IP_ADD_MEMBERSHIP参数,如:
..........
imr.imr_multiaddr.s_addr = netAddr.s_addr;
imr.imr_interface.s_addr = interfaceAddr.s_addr;
setsockopt(netPath->eventSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq);
.......... (此代码可以工作,经测试可以接收发往多播组的数据)
可是如果在自己的一个内核模块里,如何让本地网络接口加入某个多播组呢,我自己写了一个内核模块,希望在模块加载的时候,使本地网络接口加入一个组播地址(IEEE1588的多播地址 - 224.0.1.129),可是失败了,代码片段如下:
/* initialize a kernel socket which used to control eth */
sock_create_kern(PF_INET, SOCK_DGRAM, 0, &privdata->sock);
strcpy(privdata->ifr.ifr_ifrn.ifrn_name, IF_NAME);
kernel_sock_ioctl(privdata->sock, SIOCSIFNAME, (unsigned long) &privdata->ifr);
kernel_sock_ioctl(privdata->sock, SIOCGIFADDR, (unsigned long) &privdata->ifr);
ieee1588_ntoa(&privdata->ifr.ifr_ifru.ifru_addr, local_ipaddr);
printk("Local IP Addr: %s\n", local_ipaddr);
printk("Multicast IP Addr: %s\n", DEFAULT_PTP_DOMAIN_ADDRESS);
imr.imr_multiaddr.s_addr = in_aton(DEFAULT_PTP_DOMAIN_ADDRESS);
imr.imr_interface.s_addr = in_aton(local_ipaddr);
ret = kernel_setsockopt(privdata->sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &imr.imr_interface.s_addr, sizeof(struct in_addr));
if (ret) {
printk("set Multicast option failed.\n"

}
ret = kernel_setsockopt(privdata->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq));
if (ret) {
printk("set Multicast option failed.\n"

}
虽然kernel_setsockopt没有返回错误(返回0),但是本地网络接口eth0仍然无法收到发送给这个多播地址的网络数据(只能收单播)
曾经考虑过将网卡初始化为混杂模式,去收多播数据,可那不是正确的做法,太占CPU资源,正确的做法应该是加入多播组
请大家一起思考一下,怎样才能实现在内核模块里,将本地网络接口(如eth0)加入某个多播组呢,有没有其它更好的方法去接收多播数据呢(除了混杂模式,因为我并不希望做一个嗅探器)

作者: lion3875 发布时间: 2010-07-22
kernel_setsockopt
作者: Roemer 发布时间: 2010-07-23
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28