免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5002 | 回复: 3
打印 上一主题 下一主题

[内核模块] 调用netif_rx()之前需要做什么 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-05-03 17:23 |只看该作者 |倒序浏览
我用dummy做模板,实现两个网卡驱动,分别为dummy_bs,dummy_ss。其中,dummy_bs接收到上层数据后直接转发给dummy_ss,dummy_ss收到dummy_bs数据后,将数据包中的skb->dev改为自己的dev,然后调用netif_rx()提交给上层。这样让上层认为该数据是由dummy_ss接收到的。同理,dummy_ss收到上层数据也是直接转发给dummy_bs。
实验环境:VMware+Ubuntu10.04
内核版本:2.6.32.59+drm33.24
  1. static struct task_struct *task_bs_recv;//创建一个接收线程
  2. static struct net_device *dev_dummy_bs;
  3. #define WIMAX_BS 0
  4. #define WIMAX_SS 1

  5. extern int put_buff(struct sk_buff *skb, int identity);//接收函数
  6. extern struct sk_buff *get_buff(int identity);//发送函数
  7. static int numdummies = 1;


  8. static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
  9. {
  10.     int ret;
  11.         //收到上层数据后,做如下处理
  12.     skb_orphan(skb);
  13.     skb->protocol = eth_type_trans(skb, dev);
  14.     //处理完毕后,发送给dummy_ss
  15.     ret = put_buff(skb, WIMAX_BS);
  16.     if(0 == ret){
  17.         dev->stats.tx_packets++;
  18.         dev->stats.tx_bytes += skb->len;
  19.     }else{
  20.         dev->stats.tx_dropped++;
  21.     }
  22.     return NETDEV_TX_OK;
  23. }
  24. //接收函数,实现为线程,负责接收dummy_ss发送给dummy_bs的数据包
  25. int bs_recv(void *data){
  26.     int pkt_len;
  27.     struct sk_buff *skb, *new;

  28.     while(1){
  29.         set_current_state(TASK_UNINTERRUPTIBLE);
  30.                 if(kthread_should_stop()) break;
  31.                 //取出dummy_ss发过来的数据
  32.         skb = get_buff(WIMAX_BS);
  33.         if(NULL != skb){
  34.                         //因为是dummy_ss发送过来的数据包,所以skb->dev原先指的是dev_dummy_ss,在这里将其改为
  35.                         //dev_dummy_bs,让上层认为该数据由dummy_bs接收并转发给上层
  36.                         skb->dev = dev_dummy_bs;
  37.             if(likely(netif_rx(new) == NET_RX_SUCCESS)){        
  38.                 dev_dummy_bs->stats.rx_packets++;
  39.                 dev_dummy_bs->stats.rx_bytes += skb->len;
  40.             }else{
  41.                 dev_dummy_bs->stats.rx_dropped++;
  42.             }
  43.         }
  44. //        printk("bs_recv running!\n");
  45.         schedule_timeout(1000);
  46.     }

  47.         return 0;
  48. }

  49. static const struct net_device_ops dummy_netdev_ops = {
  50.     .ndo_start_xmit        = dummy_xmit,
  51.     .ndo_validate_addr        = eth_validate_addr,
  52.     .ndo_set_multicast_list     = set_multicast_list,
  53.     .ndo_set_mac_address        = dummy_set_address,
  54. };

  55. static u32 always_on(struct net_device *dev)
  56. {
  57.     return 1;
  58. }

  59. static const struct ethtool_ops dummy_ethtool_ops = {
  60.     .get_link        = always_on,
  61.     .set_tso        = ethtool_op_set_tso,
  62.     .get_tx_csum        = always_on,
  63.     .get_sg        = always_on,
  64.     .get_rx_csum        = always_on,
  65. };

  66. static void dummy_setup(struct net_device *dev)
  67. {
  68.     ether_setup(dev);

  69.     /* Initialize the device structure. */
  70.     dev->netdev_ops     = &dummy_netdev_ops;
  71.     dev->ethtool_ops    = &dummy_ethtool_ops;
  72.     //dev->header_ops    = &eth_header_ops;
  73.     dev->destructor     = free_netdev;

  74.     /* Fill in device structure with ethernet-generic values. */
  75.     dev->tx_queue_len = 100;
  76.     dev->flags |= IFF_NOARP;
  77.     dev->flags |=IFF_PROMISC;
  78.     dev->flags &= ~IFF_MULTICAST;

  79.     random_ether_addr(dev->dev_addr);

  80. }
  81. static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
  82. {
  83.     if (tb[IFLA_ADDRESS]) {
  84.         if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
  85.             return -EINVAL;
  86.         if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
  87.             return -EADDRNOTAVAIL;
  88.     }
  89.     return 0;
  90. }

  91. static struct rtnl_link_ops dummy_link_ops __read_mostly = {
  92.     .kind        = "dummy_bs",
  93.     .setup        = dummy_setup,
  94.     .validate    = dummy_validate,
  95. };

  96. /* Number of dummy devices to be set up by this module. */
  97. module_param(numdummies, int, 0);
  98. MODULE_PARM_DESC(numdummies, "Number of dummy_bs pseudo devices");

  99. //设备初始化
  100. static int __init dummy_init_one(void)
  101. {
  102.     struct net_device *dev_dummy;
  103.     int err;

  104.     dev_dummy = alloc_netdev(0, "dummy_bs%d", dummy_setup);
  105.     if (!dev_dummy)
  106.         return -ENOMEM;
  107.     dev_dummy_bs = dev_dummy;
  108.     err = dev_alloc_name(dev_dummy, dev_dummy->name);
  109.     if (err < 0)
  110.         goto err;
  111.     //netif_start_queue(dev_dummy);

  112.     dev_dummy->rtnl_link_ops = &dummy_link_ops;
  113.     err = register_netdevice(dev_dummy);
  114.     if (err < 0)
  115.         goto err;
  116.     return 0;

  117. err:
  118.     free_netdev(dev_dummy);
  119.     return err;
  120. }

  121. static int __init dummy_init_module(void)
  122. {
  123.     int i, err = 0;
  124.     //线程初始化
  125.     task_bs_recv = kthread_create(bs_recv, NULL, "bs_recv_task");
  126.     if(IS_ERR(task_bs_recv)){
  127.         printk("Unable to start kernel thread.\n");
  128.         err = PTR_ERR(task_bs_recv);
  129.         task_bs_recv = NULL;
  130.         return err;   
  131.         }
  132.     wake_up_process(task_bs_recv);

  133.     rtnl_lock();
  134.     err = __rtnl_link_register(&dummy_link_ops);

  135.     for (i = 0; i < numdummies && !err; i++)
  136.         err = dummy_init_one();
  137.     if (err < 0)
  138.         __rtnl_link_unregister(&dummy_link_ops);
  139.     rtnl_unlock();

  140.     return err;
  141. }

  142. static void __exit dummy_cleanup_module(void)
  143. {
  144.     rtnl_link_unregister(&dummy_link_ops);

  145.     if(task_bs_recv){   
  146.         kthread_stop(task_bs_recv);   
  147.         task_bs_recv = NULL;   
  148.     }   
  149. }

  150. module_init(dummy_init_module);
  151. module_exit(dummy_cleanup_module);
  152. MODULE_LICENSE("GPL");
  153. MODULE_ALIAS_RTNL_LINK("dummy_bs");
复制代码
下图是静态路由设置:

下图是加载了dummy_bs和dummy_ss后的网络设备情况:


我用ping -c 5 192.168.4.155来做测试,下图是用tcpdump对dummy_bs0和dummy_ss0抓包的结果:


目前是tcpdump能抓到包,但是ping不通,不知道问题出在哪里。我自己觉得可能是在调用netif_rx()这里出错了,请问在调用netif_rx()之前还需要做些什么呢??
请各位高手帮帮忙,看看到底哪里做错了,谢谢!

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
2 [报告]
发表于 2012-05-03 20:03 |只看该作者
回复 1# llhao86
在家没有测试环境,不过从代码上看,貌似问题不是很大。put_buff和get_buff的代码没有看到,不知道这里面lz是否正确的clone和free了skb。

   

论坛徽章:
0
3 [报告]
发表于 2012-05-04 09:32 |只看该作者
本帖最后由 llhao86 于 2012-05-04 09:34 编辑

回复 2# 瀚海书香
谢谢你的回答。
put_buff只是简单的将skb挂到一个全局指针上,get_buff则是从全局指针中取出一个skb,在里面没有做clone和free操作,从tcpdump中可以看到,dummy_bs和dummy_ss都能收到数据包,因此,put_buff和get_buff应该是成功的将数据包传递过去了。至于你说的clone和free,不使用这些会有什么影响吗???

  1. int put_buff(struct sk_buff *skb, int identity)//identity是标志位,用来判断是哪个模块在调用该函数
  2. {
  3.         if(WIMAX_BS == identity){//dummy_bs调用该函数
  4.                 if(0 == down_trylock(&head_bstoss->sem)){//加锁
  5.                         mybuff_list_add(head_bstoss, skb);//将skb挂到head_bstoss指针下,等待dummy_ss取出
  6.                         up(&sem_bstoss);//增加一个skb,该信号量加1
  7.                         up(&head_bstoss->sem);
  8.                         return 0;
  9.                 }else{
  10.                         return 1;
  11.                         }
  12.                 }       

  13.         if(WIMAX_SS == identity){//dummy_ss调用该函数
  14.                 if(0 == down_trylock(&head_sstobs->sem)){
  15.                         mybuff_list_add(head_sstobs, skb);
  16.                         up(&sem_sstobs);
  17.                         up(&head_sstobs->sem);
  18.                         return 0;
  19.                 }else{
  20.                         return 1;
  21.                         }
  22.                 }
  23.         return 1;
  24. }
  25. EXPORT_SYMBOL(put_buff);

  26. struct sk_buff *get_buff(int identity)
  27. {
  28.         struct sk_buff *ret = NULL;
  29.         if(WIMAX_SS == identity){//dummy_ss调用该函数
  30.                 if(0 == down_trylock(&head_bstoss->sem)){//加锁
  31.                         if(0 == down_trylock(&sem_bstoss)){//该信号量不为零,表明head_bstoss指针下挂有skb
  32.                                 ret = mybuff_list_get(head_bstoss);//取出一个skb,返回该skb的指针
  33.                         }else{
  34.                                 ret = NULL;//信号量为零,则返回空值
  35.                         }
  36.                         up(&head_bstoss->sem);
  37.                         return ret;
  38.                 }else{
  39.                         return ret;//加锁失败,返回空值
  40.                         }
  41.                 }

  42.         if(WIMAX_BS == identity){//dummy_bs调用该函数
  43.                 if(0 == down_trylock(&head_sstobs->sem)){
  44.                         if(0 == down_trylock(&sem_sstobs)){
  45.                                 ret = mybuff_list_get(head_sstobs);
  46.                         }else{
  47.                                 ret = NULL;
  48.                         }
  49.                         up(&head_sstobs->sem);
  50.                         return ret;
  51.                 }else{
  52.                         return ret;
  53.                         }
  54.                 }
  55.         return ret;
  56. }
  57. EXPORT_SYMBOL(get_buff);
复制代码

论坛徽章:
0
4 [报告]
发表于 2012-05-04 09:55 |只看该作者
回复 2# 瀚海书香
dummy.rar (581.57 KB, 下载次数: 29)
我把代码和脚本打包了,如果你有空的话,麻烦你帮我测试一下,不胜感激!

   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP