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 = ð_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