inetdev_init为传入设备分配和绑定ip控制块,查看其调用关系如下:
fs_initcall(inet_init)---->inet_init---->ip_init---->ip_rt_init---->devinet_init---->inetdev_event
|---->inetdev_init
|---->inetdev_destroy
inetdev_init && inetdev_destroy在devinet_init中注册通知链事件,在设备注册NETDEV_REGISTER和修改mtuNETDEV_CHANGEMTU时调用inetdev_init,在设备注销NETDEV_UNREGISTER时调用inetdev_destroy;
1 /* 为指定网络设备分配并绑定ip控制块 */ 2 static struct in_device *inetdev_init(struct net_device *dev) 3 { 4 struct in_device *in_dev; 5 int err = -ENOMEM; 6 7 ASSERT_RTNL(); 8 9 /* 分配ip地址控制块 */ 10 in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL); 11 if (!in_dev) 12 goto out; 13 /* 拷贝配置信息 */ 14 memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt, 15 sizeof(in_dev->cnf)); 16 in_dev->cnf.sysctl = NULL; 17 /* 设置所属设备 */ 18 in_dev->dev = dev; 19 20 /*分配邻居项参数 */ 21 in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl); 22 if (!in_dev->arp_parms) 23 goto out_kfree; 24 /* 若允许转发 */ 25 if (IPV4_DEVCONF(in_dev->cnf, FORWARDING)) 26 /* 禁用设备的lro功能,大包不合并 */ 27 dev_disable_lro(dev); 28 /* Reference in_dev->dev */ 29 dev_hold(dev); 30 /* Account for reference dev->ip_ptr (below) */ 31 in_dev_hold(in_dev); 32 33 err = devinet_sysctl_register(in_dev); 34 if (err) { 35 in_dev->dead = 1; 36 in_dev_put(in_dev); 37 in_dev = NULL; 38 goto out; 39 } 40 /* 组播初始化 */ 41 ip_mc_init_dev(in_dev); 42 43 /* 设备启动,则启动组播 */ 44 if (dev->flags & IFF_UP) 45 ip_mc_up(in_dev); 46 47 /* we can receive as soon as ip_ptr is set -- do this last */ 48 /* 将配置块赋值给设备ip_ptr指针 */ 49 rcu_assign_pointer(dev->ip_ptr, in_dev); 50 out: 51 return in_dev ?: ERR_PTR(err); 52 out_kfree: 53 kfree(in_dev); 54 in_dev = NULL; 55 goto out; 56 }
1 /* 销毁控制块 */ 2 static void inetdev_destroy(struct in_device *in_dev) 3 { 4 struct in_ifaddr *ifa; 5 struct net_device *dev; 6 7 ASSERT_RTNL(); 8 9 dev = in_dev->dev; 10 11 /* 设置控制块销毁标记 */ 12 in_dev->dead = 1; 13 14 /* 销毁组播 */ 15 ip_mc_destroy_dev(in_dev); 16 17 /* 遍历ip地址列表 */ 18 while ((ifa = in_dev->ifa_list) != NULL) { 19 /* 删除地址 */ 20 inet_del_ifa(in_dev, &in_dev->ifa_list, 0); 21 inet_free_ifa(ifa); 22 } 23 24 /* 设备的ip控制块赋值为NULL */ 25 RCU_INIT_POINTER(dev->ip_ptr, NULL); 26 27 /* sysctl注销 */ 28 devinet_sysctl_unregister(in_dev); 29 30 /* 释放邻居项参数 */ 31 neigh_parms_release(&arp_tbl, in_dev->arp_parms); 32 33 /* 关闭arp */ 34 arp_ifdown(dev); 35 36 /* 减少ip控制块引用 */ 37 call_rcu(&in_dev->rcu_head, in_dev_rcu_put); 38 }