Something about loopback in linux code

10 篇文章 0 订阅
7 篇文章 0 订阅

before start to say

linux code 3.16.44
内核来说只能建立一个lo(loopback口)
drivers/net/loopback.c 
中定义了loopback dev的初始化和销毁的操作
在内核中这个只用了一次并且没有开放接口

 static void loopback_dev_free(struct net_device *dev)
 {       
        /* 3.16 has this line but not 2.6.32
        */
         dev_net(dev)->loopback_dev = NULL;
         free_percpu(dev->lstats);
         free_netdev(dev);
 }       
这个函数中的 net->loopback 很重要,发往本地数据包,dst dev 至少很多通过
 net->loopback,赋值的,如果执行了loopback_dev_free 比如路由的 dst dev
  就为空,但路由不知道,内核就挂了

而在内核中这个函数除非是在系统推出,否则不会被调到的

loopback 初始化流程

其他的net设备其实也是这样

  • step 01
 struct net_device *dev;
 dev = alloc_netdev(0, "lo", loopback_setup);

 /*********
 alloc_netdev() 分配空间并调动 loopback_setuo
 struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
                void (*setup)(struct net_device *),                   
                unsigned int txqs, unsigned int rxqs) {
    ...
    setup(dev);
    ...
}
static void loopback_setup(struct net_device *dev) {
    ...

dev->ethtool_ops        = &loopback_ethtool_
dev->header_ops         = &eth_header_ops;  
dev->netdev_ops         = &loopback_ops;    /**/
dev->destructor         = loopback_dev_free; 
}
loopback_setup会设置一些设备操作,还有设备的析构函数
************/

-step 02

 dev_net_set(dev, net);
err = register_netdev(dev);
 /*********
 注册netdevice设备, 3.16是注册到hash 表中,2.6.32是到链表中, 所有
 在 /proc/net/dev 下,2.6是按网卡名称排序(以为网卡名是按pci总线地址
 初始化接口时按先后顺序分配的,因而也是按这个顺序加到链表里的),
 3.16shi无顺序的

 ***********/
  • step03
net->loopback_dev = dev;
/****
将net->loopback 指向 这个dev设备
*****/

使用过程中

这个回环接口很多地方用到了。。。。

loopback 解注册流程

unregister_netdev(dev)

/*****
这个里边做了很多事。想象一下,及时不是loopback接口,其他网口,
在解注册是肯定有可能很多操作都在使用,如果直接摘链释放,那问题一定很多
 void unregister_netdev(struct net_device *dev)
 {                                             
         rtnl_lock();                          
         unregister_netdevice(dev);            
         rtnl_unlock();                        
 }                                             

 操作的时候加锁,unregister_netdev 是开放的接口,unregister_netdevice 不是。
 他只是unregister_netdevice_queue的直接封装

  void unregister_netdevice_queue(struct net_device *dev, struct list_head *head) /*head = NULL*/
 {
         ASSERT_RTNL();

         if (head) {
                 list_move_tail(&dev->unreg_list, head);
         } else {
                 rollback_registered(dev);
                 /* Finish processing unregister after unlock */
                 net_set_todo(dev);
         }                                                                      
 }
直接调用rollback_registered()
掉入
rollback_registered_many(struct list_head *head){
    ...
    /*没关闭的先关闭*/
    list_for_each_entry(dev, head, unreg_list)           
        list_add_tail(&dev->close_list, &close_head);
    dev_close_many(&close_head);                         

    synchronize_net();  /*RCU 同步*/
    list_for_each_entry(dev, head, unreg_list) {                    
        /* Shutdown queueing discipline.*/                     
        dev_shutdown(dev);                                      

        /* Notify protocols, that we are about to destroy       
           this device. They should clean all the things. 
           通知其他模块要解注册了
        */                                                      
        call_netdevice_notifiers(NETDEV_UNREGISTER, dev);       

        dev_uc_flush(dev);                                      
        dev_mc_flush(dev);                                      

        if (dev->netdev_ops->ndo_uninit)                        
                dev->netdev_ops->ndo_uninit(dev);               

        if (!dev->rtnl_link_ops ||                              
            dev->rtnl_link_state == RTNL_LINK_INITIALIZED)      
                rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL);

        /* Notifier chain MUST detach us all upper devices. */  
        WARN_ON(netdev_has_any_upper_dev(dev));                 

        /* Remove entries from kobject tree */                  
        netdev_unregister_kobject(dev);                         
        netif_reset_xps_queues_gt(dev, 0);                      

    }        
    synchronize_net(); /*RCU 同步*/
    /*引用计数减一*/
    list_for_each_entry(dev, head, unreg_list)
        dev_put(dev);                     
}

******

attached call_netdevice_notifiers(NETDEV_UNREGISTER, dev)

    /*以路由模块为例,收到`NETDEV_UNREGISTER`通知后*/
tatic int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr){
            struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct in_device *in_dev;
        struct net *net = dev_net(dev);

        if (event == NETDEV_UNREGISTER) {                         
                fib_disable_ip(dev, 2);
                rt_flush_dev(dev);
                return NOTIFY_DONE;
        }

        in_dev = __in_dev_get_rtnl(dev);
        if (!in_dev)
                return NOTIFY_DONE;

        .....
}
/*一下这个函数中就用到了net->loopback_dev*/
void rt_flush_dev(struct net_device *dev)
{
        if (!list_empty(&rt_uncached_list)) {
                struct net *net = dev_net(dev);
                struct rtable *rt;

                spin_lock_bh(&rt_uncached_lock);

                /*如果在路由表的出接口设备中查到有要解注册的设备,
                就把这个设备指向net->loopback_dev
                这个操作默认lo 从来不会被释放*/

                list_for_each_entry(rt, &rt_uncached_list, rt_uncached) {
                        if (rt->dst.dev != dev)
                                continue;
                        rt->dst.dev = net->loopback_dev;
                        dev_hold(rt->dst.dev);                            
                        dev_put(dev);
                }
                spin_unlock_bh(&rt_uncached_lock);
        }
}

Conclusion

 loopback 还是有点特殊性的
 如果改造源码,想要在系统中创建多个loopback,那么你的初始化中一定不要使用默认的loopback_dev_free ,要重载他,因为他改了 net->loopback
 and more

Contact: bigjordon@163.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值